structured-outputs changedbuild-with-claude/structured-outputs
Nearest release: v2.1.312, published under an hour before this site recorded the change. Shown because the two are within 24 hours of each other. Nothing here says the release caused the edit.
Recorded here
Lines+38added
Lines−38removed
From line
33
where the diff opens
First seen
14 Aug 2026
this site's first read of the page
Recorded edits25to this page, all time
The whole hunk
from line 33, old and new numbered
/
from line 33
3333 Microsoft Foundry: ga
3434---
3535
36Structured outputs constrain Claude's responses to follow a specific schema, ensuring valid, parseable output for downstream processing. Structured outputs provide two complementary features:
36Structured outputs constrain Claude’s responses to follow a specific schema, ensuring valid, parseable output for downstream processing. Structured outputs provide two complementary features:
3737
38* **JSON outputs** (`output_config.format`): Get Claude's response in a specific JSON format, for example to extract data from images or text, generate structured reports, or format API responses. This page covers JSON outputs.
38* **JSON outputs** (`output_config.format`): Get Claude’s response in a specific JSON format, for example to extract data from images or text, generate structured reports, or format API responses. This page covers JSON outputs.
3939* **Strict tool use** (`strict: true`): Guarantee schema validation on tool names and inputs. See [Strict tool use](https://platform.claude.com/docs/en/agents-and-tools/tool-use/strict-tool-use).
4040
4141You can use these features independently or [together in the same request](https://platform.claude.com/docs/en/build-with-claude/structured-outputs#using-both-features-together).
from line 67
6767 </Step>
6868
6969 <Step title="Read the response">
70 Claude returns valid JSON that matches your schema in the response's text content block. SDK helpers parse it into your type.
70 Claude returns valid JSON that matches your schema in the response’s text content block. SDK helpers parse it into your type.
7171 </Step>
7272</Steps>
7373
from line 108
108108 }'
109109 ```
110110
111 Claude returns JSON like this in the response's text content block:
111 Claude returns JSON like this in the response’s text content block:
112112
113113 ```json Output
114114 {
from line 146
146146 YAML
147147 ```
148148
149 Claude returns JSON like this in the response's text content block:
149 Claude returns JSON like this in the response’s text content block:
150150
151151 ```json Output
152152 {
from line 192
192192 print(response.parsed_output)
193193 ```
194194
195 Pass a [Pydantic](https://docs.pydantic.dev/) model to `client.messages.parse()`, the recommended method, as `output_format`. The SDK transforms the model's schema, sends it as `output_config.format`, validates the response, and returns the parsed model in `parsed_output`.
195 Pass a [Pydantic](https://docs.pydantic.dev/) model to `client.messages.parse()`, the recommended method, as `output_format`. The SDK transforms the model’s schema, sends it as `output_config.format`, validates the response, and returns the parsed model in `parsed_output`.
196196
197197 The previous example outputs:
198198
from line 370
370370 }
371371 ```
372372
373 When you pass a Java class to `outputConfig()`, the SDK derives a JSON schema from it and validates the schema. The builder then produces a `StructuredMessageCreateParams<T>`. Rather than transforming the schema, the SDK's local validation rejects [constraints not supported by the API](https://platform.claude.com/docs/en/build-with-claude/structured-outputs#json-schema-limitations). Read the parsed result with `response.content().stream().flatMap(block -> block.text().stream()).findFirst().orElseThrow().text()`.
373 When you pass a Java class to `outputConfig()`, the SDK derives a JSON schema from it and validates the schema. The builder then produces a `StructuredMessageCreateParams<T>`. Rather than transforming the schema, the SDK’s local validation rejects [constraints not supported by the API](https://platform.claude.com/docs/en/build-with-claude/structured-outputs#json-schema-limitations). Read the parsed result with `response.content().stream().flatMap(block -> block.text().stream()).findFirst().orElseThrow().text()`.
374374
375375 The previous example outputs:
376376
from line 383
383383 </Note>
384384
385385 <Accordion title="Generic type erasure">
386 Java retains generic type information for fields in the class's metadata, but generic type erasure applies in other scopes. Although a JSON schema can be derived from a `BookList.books` field with type `List<Book>`, a valid JSON schema cannot be derived from a local variable of that same type.
386 Java retains generic type information for fields in the class’s metadata, but generic type erasure applies in other scopes. Although a JSON schema can be derived from a `BookList.books` field with type `List<Book>`, a valid JSON schema cannot be derived from a local variable of that same type.
387387
388388 If an error occurs while converting a JSON response to a Java class instance, the error message includes the JSON response to help with diagnosis. If your JSON response might contain sensitive information, avoid logging it directly, or ensure that you redact any sensitive details from the error message.
389389 </Accordion>
from line 558
558558 }
559559 ```
560560
561 Local validation checks that you haven't used any unsupported constraint keywords, but constraint values aren't validated locally. For example, an unsupported `"format"` value might pass local validation but cause a remote error.
561 Local validation checks that you haven’t used any unsupported constraint keywords, but constraint values aren’t validated locally. For example, an unsupported `"format"` value might pass local validation but cause a remote error.
562562
563563 If you use both Jackson and Swagger annotations to set the same schema field, the Jackson annotation takes precedence.
564564 </Accordion>
from line 601
601601 }
602602 ```
603603
604 Define a class that implements `StructuredOutputModel` and uses `StructuredOutputModelTrait`, and pass its name in `outputConfig: ['format' => MyClass::class]`. The SDK derives a JSON schema from the class's PHP 8 property types, transforms it, and returns a typed instance from `$message->parsedOutput()`.
604 Define a class that implements `StructuredOutputModel` and uses `StructuredOutputModelTrait`, and pass its name in `outputConfig: ['format' => MyClass::class]`. The SDK derives a JSON schema from the class’s PHP 8 property types, transforms it, and returns a typed instance from `$message->parsedOutput()`.
605605
606606 `parsedOutput()` returns your model instance on success, or `null` (or an error array) if parsing fails. Use `instanceof` to narrow the type before accessing fields.
607607
from line 696
696696 puts contact
697697 ```
698698
699 Define a class that extends `Anthropic::BaseModel` and pass it to `messages.create()` as `output_config: {format: Model}`. The SDK derives a JSON schema from the class, transforms it, and assigns the parsed result to the response's `parsed_output` attribute as a typed Ruby object.
699 Define a class that extends `Anthropic::BaseModel` and pass it to `messages.create()` as `output_config: {format: Model}`. The SDK derives a JSON schema from the class, transforms it, and assigns the parsed result to the response’s `parsed_output` attribute as a typed Ruby object.
700700
701701 The previous example outputs:
702702
from line 741
741741Most SDK helpers transform schemas that use unsupported features. The transformation steps:
742742
7437431. **Remove unsupported constraints** (for example, `minimum`, `maximum`, `minLength`, `maxLength`)
7442. **Update descriptions** by adding each unsupported constraint to the field's description (for example, `{minimum: 100}`)
7442. **Update descriptions** by adding each unsupported constraint to the field’s description (for example, `{minimum: 100}`)
7457453. **Add `additionalProperties: false`** to all objects
7467464. **Filter string formats** to the supported list only
7477475. **Validate responses** against your original schema and all its constraints, if the helper validates responses
from line 748
748748
749749Claude receives a simplified schema, but a helper that validates responses still enforces every constraint in your code.
750750
751**Example:** A field with `minimum: 100` becomes a plain integer in the sent schema, and the SDK adds `{minimum: 100}` to the field's description. A helper that validates responses still checks the response against `minimum: 100`.
751**Example:** A field with `minimum: 100` becomes a plain integer in the sent schema, and the SDK adds `{minimum: 100}` to the field’s description. A helper that validates responses still checks the response against `minimum: 100`.
752752
753753## Using a raw JSON schema
754754
from line 789
789789 }'
790790 ```
791791
792 Claude returns JSON like this in the response's text content block:
792 Claude returns JSON like this in the response’s text content block:
793793
794794 ```json Output
795795 {
from line 827
827827 YAML
828828 ```
829829
830 Claude returns JSON like this in the response's text content block:
830 Claude returns JSON like this in the response’s text content block:
831831
832832 ```json Output
833833 {
from line 922
922922
923923 Use `jsonSchemaOutputFormat()` to pass a plain JSON schema to `parse()`, without installing Zod. The API returns a response that conforms to the schema, and if you declare the schema with `as const`, TypeScript automatically infers the type for `parsed_output` according to your schema. For an imported or generated schema, `parsed_output` is typed as `unknown`.
924924
925 By default, the helper [transforms the schema](https://platform.claude.com/docs/en/build-with-claude/structured-outputs#how-sdk-transformation-works) the same way `zodOutputFormat()` does. Pass `{ transform: false }` as the second argument to send it unchanged. Unlike `zodOutputFormat()`, it doesn't validate the response, so it doesn't catch violations of [constraints not supported by the API](https://platform.claude.com/docs/en/build-with-claude/structured-outputs#json-schema-limitations), such as `minimum`.
925 By default, the helper [transforms the schema](https://platform.claude.com/docs/en/build-with-claude/structured-outputs#how-sdk-transformation-works) the same way `zodOutputFormat()` does. Pass `{ transform: false }` as the second argument to send it unchanged. Unlike `zodOutputFormat()`, it doesn’t validate the response, so it doesn’t catch violations of [constraints not supported by the API](https://platform.claude.com/docs/en/build-with-claude/structured-outputs#json-schema-limitations), such as `minimum`.
926926
927927 The previous example outputs:
928928
from line 2168
21682168
21692169JSON outputs and strict tool use solve different problems and work together:
21702170
2171* **JSON outputs** control Claude's response format (what Claude says).
2171* **JSON outputs** control Claude’s response format (what Claude says).
21722172* **Strict tool use** validates tool parameters (how Claude calls your functions).
21732173
21742174When combined, Claude can call tools with guaranteed-valid parameters AND return structured JSON responses. This is useful for agentic workflows where you need both reliable tool calls and structured final outputs.
from line 2640
26402640 * Array constraints beyond `minItems` of 0 or 1
26412641 * `additionalProperties` set to anything other than `false`
26422642
2643 If you use an unsupported feature, you'll receive a 400 error with details.
2643 If you use an unsupported feature, you’ll receive a 400 error with details.
26442644</Accordion>
26452645
26462646<Accordion title="Pattern support (regex)">
from line 2714
27142714Claude maintains its safety and helpfulness properties even when using structured outputs. If Claude refuses a request for safety reasons:
27152715
27162716* The response has `stop_reason: "refusal"`.
2717* You'll receive a 200 status code.
2718* You'll be billed for the tokens generated.
2717* You’ll receive a 200 status code.
2718* You’ll be billed for the tokens generated.
27192719* The output might not match your schema because the refusal message takes precedence over schema constraints.
27202720
2721A property that asks for the model's thinking or step-by-step reasoning might lead to a `reasoning_extraction` refusal. Ask for a short explanation instead. See [Keep reasoning in thinking blocks](https://platform.claude.com/docs/en/build-with-claude/refusals-and-fallback#keep-reasoning-in-thinking-blocks).
2721A property that asks for the model’s thinking or step-by-step reasoning might lead to a `reasoning_extraction` refusal. Ask for a short explanation instead. See [Keep reasoning in thinking blocks](https://platform.claude.com/docs/en/build-with-claude/refusals-and-fallback#keep-reasoning-in-thinking-blocks).
27222722
27232723**Token limit reached** (`stop_reason: "max_tokens"`)
27242724
from line 2730
27302730
27312731**Enum value casing**
27322732
2733Structured outputs don't guarantee the capitalization of string `enum` and `const` values: Claude might return a value that differs from your schema only in capitalization, typically in the first letter of a word following a space. For example, given this schema:
2733Structured outputs don’t guarantee the capitalization of string `enum` and `const` values: Claude might return a value that differs from your schema only in capitalization, typically in the first letter of a word following a space. For example, given this schema:
27342734
27352735```json
27362736{
from line 2739
27392739}
27402740```
27412741
2742The output might contain `"Conversation Topic 3"` (capital "T") even though that exact value isn't in the enum. The response completes normally, with no error and no special `stop_reason`. This applies to both JSON outputs and strict tool use. Compare enum values case-insensitively, and avoid enum values that differ only in capitalization.
2742The output might contain `"Conversation Topic 3"` (capital “T”) even though that exact value isn’t in the enum. The response completes normally, with no error and no special `stop_reason`. This applies to both JSON outputs and strict tool use. Compare enum values case-insensitively, and avoid enum values that differ only in capitalization.
27432743
27442744### Schema complexity limits
27452745
2746Structured outputs work by compiling your JSON schemas into a grammar that constrains Claude's output. More complex schemas produce larger grammars that take longer to compile. To protect against excessive compilation times, the API enforces several complexity limits.
2746Structured outputs work by compiling your JSON schemas into a grammar that constrains Claude’s output. More complex schemas produce larger grammars that take longer to compile. To protect against excessive compilation times, the API enforces several complexity limits.
27472747
27482748#### Explicit limits
27492749
from line 2751
27512751
27522752| Limit | Value | Description |
27532753| --------------------------- | ----- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
2754| Strict tools per request | 20 | Maximum number of tools with `strict: true`. Non-strict tools don't count toward this limit. |
2754| Strict tools per request | 20 | Maximum number of tools with `strict: true`. Non-strict tools don’t count toward this limit. |
27552755| Optional parameters | 24 | Total optional parameters across all strict tool schemas and JSON output schemas. Each parameter not listed in `required` counts toward this limit. |
27562756| Parameters with union types | 16 | Total parameters that use `anyOf` or type arrays (for example, `"type": ["string", "null"]`) across all strict schemas. These are especially expensive because they create exponential compilation cost. |
27572757
27582758<Note>
2759 These limits apply to the combined total across all strict schemas in a single request. For example, if you have 4 strict tools with 6 optional parameters each, you'll reach the 24-parameter limit even though no single tool seems complex.
2759 These limits apply to the combined total across all strict schemas in a single request. For example, if you have 4 strict tools with 6 optional parameters each, you’ll reach the 24-parameter limit even though no single tool seems complex.
27602760</Note>
27612761
27622762#### Additional internal limits
27632763
2764Beyond the explicit limits in the preceding table, there are additional internal limits on the compiled grammar size. These limits exist because schema complexity doesn't reduce to a single dimension: features such as optional parameters, union types, nested objects, and number of tools interact with each other in ways that can make the compiled grammar disproportionately large.
2764Beyond the explicit limits in the preceding table, there are additional internal limits on the compiled grammar size. These limits exist because schema complexity doesn’t reduce to a single dimension: features such as optional parameters, union types, nested objects, and number of tools interact with each other in ways that can make the compiled grammar disproportionately large.
27652765
2766When these limits are exceeded, you'll receive a 400 error with the message "Schema is too complex for compilation." These errors mean the combined complexity of your schemas exceeds what can be efficiently compiled, even if each individual limit in the preceding table is satisfied. As a final stop-gap, the API also enforces a **compilation timeout of 180 seconds**. Schemas that pass all explicit checks but produce very large compiled grammars might hit this timeout.
2766When these limits are exceeded, you’ll receive a 400 error with the message “Schema is too complex for compilation.” These errors mean the combined complexity of your schemas exceeds what can be efficiently compiled, even if each individual limit in the preceding table is satisfied. As a final stop-gap, the API also enforces a **compilation timeout of 180 seconds**. Schemas that pass all explicit checks but produce very large compiled grammars might hit this timeout.
27672767
27682768#### Tips for reducing schema complexity
27692769
2770If you're hitting complexity limits, try these strategies in order:
2770If you’re hitting complexity limits, try these strategies in order:
27712771
27721. **Mark only critical tools as strict.** If you have many tools, reserve strict tool use for those where schema violations cause real problems, and rely on Claude's natural adherence for simpler tools.
27721. **Mark only critical tools as strict.** If you have many tools, reserve strict tool use for those where schema violations cause real problems, and rely on Claude’s natural adherence for simpler tools.
27732773
27742. **Reduce optional parameters.** Make parameters `required` where possible. Each optional parameter roughly doubles a portion of the grammar's state space. If a parameter always has a reasonable default, consider making it required and having Claude provide that default explicitly.
27742. **Reduce optional parameters.** Make parameters `required` where possible. Each optional parameter roughly doubles a portion of the grammar’s state space. If a parameter always has a reasonable default, consider making it required and having Claude provide that default explicitly.
27752775
277627763. **Simplify nested structures.** Deeply nested objects with optional fields compound the complexity. Flatten structures where possible.
27772777
from line 2808
28082808* **Message prefilling:** Prefilling is incompatible with JSON outputs.
28092809
28102810<Tip>
2811 **Grammar scope:** Grammars apply only to Claude's direct output, not to tool use calls, tool results, or thinking tags (when using [thinking](https://platform.claude.com/docs/en/build-with-claude/thinking)). Grammar state resets between sections, allowing Claude to think freely while still producing structured output in the final response.
2811 **Grammar scope:** Grammars apply only to Claude’s direct output, not to tool use calls, tool results, or thinking tags (when using [thinking](https://platform.claude.com/docs/en/build-with-claude/thinking)). Grammar state resets between sections, allowing Claude to think freely while still producing structured output in the final response.
28122812</Tip>
28132813
28142814## Next steps
from line 2819
28192819 </Card>
28202820
28212821 <Card title="Strict tool use" icon="check" href="https://platform.claude.com/docs/en/agents-and-tools/tool-use/strict-tool-use">
2822 Enforce JSON Schema compliance on Claude's tool inputs with grammar-constrained sampling.
2822 Enforce JSON Schema compliance on Claude’s tool inputs with grammar-constrained sampling.
28232823 </Card>
28242824
28252825 <Card title="Tool use with Claude" icon="wrench" href="https://platform.claude.com/docs/en/agents-and-tools/tool-use/overview">
from line 2827
28272827 </Card>
28282828
28292829 <Card title="Pricing" icon="calculator" href="https://platform.claude.com/docs/en/about-claude/pricing">
2830 Learn about Anthropic's pricing structure for models and features.
2830 Learn about Anthropic’s pricing structure for models and features.
28312831 </Card>
28322832</CardGroup>
28332833
No line in this hunk matches that.