Whetstone.
Designing a Claude ApplicationStructured outputs and citations
Module 2, Lesson 324 min

Structured outputs and citations

You want JSON out. Historically you asked nicely, prefilled an open brace, and wrote a parser with a retry. Two of those three are now unnecessary and one of them returns 400.

Then there is the sentence that ruins somebody’s architecture diagram roughly once a quarter: the two features in this lesson do not compose.

output_config.format is the current spelling

Structured outputs is GA for Claude 4.5 and later, no beta header. You declare the shape you want and the response conforms to it.

The field is output_config.format. You will also encounter output_format, which is transitional: it exists, it turns up in older examples, and it is not what you should write in new code. Note the precise claim there, because the difference matters and the exam knows it. Transitional means superseded and still working. It does not mean removed, and it does not mean 400.

This is the proper replacement for last-turn assistant prefill. Prefill forced a format by exploiting completion behaviour and gave you no guarantee. Structured outputs is a declared contract. And since prefill on the final assistant turn now returns 400 on Claude 4.6 and later, the migration is not optional for anyone on a current model.

Citations

Citations is also GA. It makes the model attribute claims back to spans in the documents you supplied, rather than asserting things and leaving you to trust it.

The design value is specific: an unattributed answer and a hallucinated answer look identical. Citations turn that into something checkable. If your requirements say anything about verifiability, provenance, or “the user must be able to see where this came from”, citations is the feature the question is fishing for.

The combination that returns 400

The design answers, if you hit this in real life:

Split the call. One request with citations to gather and attribute, a second cheap call to reshape the result into your schema. Two calls, more tokens, but both halves work.

Drop the schema and parse. Take citations, accept prose, and extract afterwards. You lose the guarantee.

Drop citations and carry provenance yourself. Keep the schema, add a field for source ids, and instruct the model to fill it. You lose the real attribution and gain a field the model can be wrong about, which is worse than it looks: a provenance field the model populates has the shape of evidence without the substance of it, and reviewers will trust it exactly as if it were real.

There is no fourth option where both work, and a question offering you one is offering you the distractor. Notice the failure direction though: 400 is loud. You find this in development, not in a customer’s hands, which is the difference between an annoying constraint and an incident.

Practice

Try it yourself

Quiz

The combination that fails

You are building a research tool that must return JSON matching a schema, with a citation for every claim. What happens?

  1. AIt works, and citations appear as an extra field alongside your schema
  2. BThe request returns 400, because citations and structured outputs cannot be combined
  3. CIt works, but the citations are silently dropped so only schema-shaped JSON comes back
  4. DThe request succeeds once you add the correct beta header to enable the combination
Show answer

Correct answer: B — The request returns 400, because citations and structured outputs cannot be combined

Citations and structured outputs together return 400. This is a hard rejection, not a degradation, which is the good direction to fail in but still means your design does not work as specified. Silent dropping is the tempting answer because that is how a lot of feature conflicts behave, and quietly losing citations in a research tool would be far worse than a 400 you notice in development.

Recall

The current spelling

Two field names exist for the same feature and only one of them is current.

What is the current field for structured outputs, what is the older one called, and which models support the feature?

Reveal answer

output_config.format is the current field. output_format is transitional, so you will still see it and it still appears in older material, but new code should use output_config.format. Structured outputs is GA, no beta header, for Claude 4.5 and later. Note the same output_config object also carries effort, which is the adaptive-thinking control.

Quiz

Which of these two is the current form

Both of these appear in code you have inherited. Both were written this year.

Form A
{
  "model": "claude-sonnet-5",
  "max_tokens": 1024,
  "output_format": { "type": "json_schema", "schema": { "type": "object" } },
  "messages": []
}
Form B
{
  "model": "claude-sonnet-5",
  "max_tokens": 1024,
  "output_config": { "format": { "type": "json_schema", "schema": { "type": "object" } } },
  "messages": []
}
  1. AA is current and B is a typo introduced by a bad autocomplete
  2. BA is current, B is the deprecated form that returns 400
  3. CB is current, A is transitional and should not be used in new code
  4. DThey are aliases with no difference at all, so either is fine forever
Show answer

Correct answer: C — B is current, A is transitional and should not be used in new code

output_config.format is the current field and output_format is transitional: it still exists and still turns up in older examples, which is exactly why it survives in real codebases. The tempting answer is that the older form returns 400, because this course is full of hard rejections and pattern-matching to that would feel consistent. It does not: this one is a naming migration rather than a removal, and overstating a deprecation is its own error. The reason to prefer output_config is that it is where effort also lives.

Quiz

Which models get structured outputs

You want structured outputs on a cost-sensitive workload. Which of these model ids supports the feature?

  1. Aclaude-opus-4-5-20251101
  2. Bclaude-sonnet-4-5-20250929
  3. Cclaude-opus-4-6
  4. DAll of the above, since structured outputs is GA
Show answer

Correct answer: B — claude-sonnet-4-5-20250929

Structured outputs is GA for Claude 4.5 and later, so a 4.5 Sonnet qualifies. The all-of-the-above option is the trap, built on a misreading of what GA means. GA describes the feature's release status, not universal model coverage, and reading a release status as a coverage guarantee is the error being tested. Read the version floor, not the vibe.

Recall

What you do when the 400 lands on your design

Knowing the constraint is half a mark. Knowing what a competent architect does next is the other half, and it is the half that gets asked as a scenario.

Citations and structured outputs cannot be combined. What are the three ways round it, and what does each one actually cost you?

Reveal answer

Split the call: one request with citations to gather and attribute, a second cheap call to reshape the result into your schema. Costs you extra tokens and a second round trip, and both halves genuinely work. Drop the schema and parse: take citations, accept prose, extract afterwards. Costs you the conformance guarantee. Drop citations and carry provenance yourself: keep the schema, add a source-id field and instruct the model to fill it. Costs you real attribution and replaces it with a field the model can be wrong about, which is worse than it looks because it produces the appearance of provenance. There is no fourth option where both work on one request.

Check

Replace a prefill hack on paper

Find or imagine a place where you would have used assistant prefill to force JSON, and rewrite the plan.

You should see

The design uses output_config.format with an explicit schema rather than an assistant message ending in an open brace, and you can state why the old approach is no longer merely discouraged but returns 400 on 4.6 and later.

Sign in to track your progress →