Skip to lesson

AnthropicClaude Certified Architect – Foundations2026-104.3 Enforce structured output using tool use and JSON schemas

Route structured failures by their cause

Completed by the knowledge check

Learning objective

Handle residual structured-output failures: unsupported schema features, refusals, max_tokens truncation, and an absent tool call under auto.

Core idea

Structured output changes which failures you should expect; it does not remove outcome handling. A rejected schema never produces a record. A refusal can arrive as HTTP 200. A token limit can leave an incomplete response. Under tool_choice: {"type": "auto"}, a strict extraction tool can remain unused.

For a document-extraction service, classify the failure before choosing recovery. Changing max_tokens addresses a truncated generation. It does not repair an unsupported schema or make auto compulsory. A stronger prompt can influence a tool choice, but it does not replace supported forcing or a native JSON contract.

See 4.3.2 for choosing native JSON or strict tool use and 4.3.3 for document routing. This lesson owns the residual failure paths after that choice. A consumer should accept only a complete result on the intended output surface, then apply the semantic checks in 4.3.6.

How it works

Repair an unsupported request

JSON outputs and strict tool use share a supported JSON Schema subset. Anthropic documents a 400 error when a schema uses unsupported features. Examples include numeric constraints such as minimum, maximum, and multipleOf; recursive schemas; external $ref references; and string minLength or maxLength. Retrying the unchanged schema does not remove the rejected feature.

Inspect the error and simplify the schema or use a documented SDK transformation. In Python, transform_schema() from the anthropic package returns a transformed schema without sending a request. The Python client.messages.parse() helper transforms a Pydantic model’s schema, sends it as output_config.format, validates the response, and returns parsed_output.

Transformation can strip an unsupported bound and append it to the field’s description. That changes enforcement: the API receives a simpler constraint, and local validation must still check the original bound. Not every helper performs that check. The TypeScript jsonSchemaOutputFormat() helper transforms a raw schema by default but does not validate the response against stripped constraints. Do not treat transformation alone as proof that the full original contract holds.

The request combination also matters. Enabling citations with output_config.format returns 400 because citation blocks require interleaving with text. Choose a compatible output design rather than retrying that combination.

Handle refusal before parsing a record

With structured outputs, stop_reason: "refusal" can accompany HTTP 200, and refusal takes precedence over schema constraints. Check stop_reason before treating the content as the requested JSON or extraction input. A refusal is a response outcome, not evidence that a JSON parser is defective.

Anthropic documents stop_details.category and stop_details.explanation for refusal diagnostics. The category and explanation can be null; handle that as a valid diagnostic outcome. The explanation is human-readable text whose wording is not stable. Do not parse it as a machine-readable classification. Discard partial output from a mid-stream refusal.

A schema field or prompt that asks for private thinking can trigger reasoning_extraction. Inspect field names such as reasoning or trace, the system prompt, and tool descriptions. Ask for a short explanation or supporting evidence instead of internal reasoning. Anthropic documents no recommended fallback for this category: change the request rather than repeat it unchanged. Other refusal routing belongs to the broader response handling in 1.1.1; it is separate from schema repair.

Regenerate a truncated record

When stop_reason: "max_tokens" appears, the response reached the request’s token limit. Structured output can be incomplete and fail the schema. For this path, Anthropic recommends retrying with a higher max_tokens value. Its stop-reason documentation gives the same remedy for an incomplete tool_use block.

Do not insert a missing brace, invent absent fields, or execute an incomplete extraction call. Those repairs can produce parseable content without recovering the generated record. Keep the original source and schema for the retry so the extra output budget addresses the actual cause.

A successful retry still needs the semantic checks in 4.3.6. A complete record can contain a wrong total or a date assigned to the wrong field; increasing the output budget repairs incompleteness, not those errors.

Treat an absent call as an explicit outcome

strict: true constrains a tool call’s name and input when the model makes that call. It does not require a call under tool_choice: {"type": "auto"}. If response.content has no matching tool_use block, return the application’s missing-extraction outcome rather than dereference a nonexistent input or parse arbitrary prose as if it were the tool result.

Where supported, tool_choice: {"type": "any"} requires a tool call, while tool_choice: {"type": "tool", "name": "extract_invoice"} requires the named tool. Claude Opus 5.5, Claude Sonnet 5.5, Claude Fable 5.1, and Claude Mythos 5.1 reject any and tool with 400. Manual extended thinking through thinking: {type: "enabled"} also does not support those choices. See 4.3.3 for the routing design; do not turn a missing call into an unsupported forced request.

On a supported native-JSON path, output_config.format makes the response text the contracted data surface. That is an intentional interface choice, distinct from rescuing free-form text returned under auto.

Key distinctions and trade-offs

Choose recovery from the observable cause:

ObservationClassificationAppropriate next action
400 naming an unsupported schema featureRequest contract rejectedRemove or transform the unsupported feature and retain necessary local validation
HTTP 200 with stop_reason: "refusal"Refused outputRead refusal diagnostics and handle the cause before parsing
stop_reason: "max_tokens"Incomplete generationRetry with a higher supported max_tokens
No extraction tool_use under autoTool selection did not produce the recordHandle the missing result and choose a supported output guarantee

A further documented exception concerns string enum and const capitalization. Both native JSON outputs and strict tool use can return a casing variant without an error or special stop_reason. Anthropic recommends case-insensitive comparison and avoiding enum values that differ only by capitalization. If your consumer needs exact spelling, map a case-insensitive match to the declared canonical value; reject anything that is not such a match.

Architecture / decision scenario

An invoice service observes four failures. A raw schema containing minimum returns 400. Another request completes with refusal after asking for a private reasoning trace. A large line-item record stops at max_tokens. A fourth response under auto contains text but no extract_invoice call.

The service repairs the first request’s unsupported constraint and preserves its local bound check. It removes the private-trace requirement from the second request, asking for short supporting evidence instead. It discards the third response and retries the same extraction with a larger supported max_tokens. It reports the fourth as missing extraction, then changes the interface to supported forcing or native JSON according to the deployed model.

Each path produces either an explicit unsuccessful outcome or a complete record ready for semantic checks. The consumer also canonicalizes documented enum casing variants. One generic “retry failed JSON” branch would obscure the four failures and the casing variant, and repeat requests that need a different change.

Common exam traps

  • Retrying a 400 with the same unsupported schema.
  • Assuming every schema-transforming SDK helper validates the original constraints.
  • Treating HTTP 200 as proof that structured extraction succeeded.
  • Repairing truncated JSON instead of obtaining the complete generation.
  • Expecting strict: true to require a call under auto.
  • Forcing any or tool on a model or thinking setting that rejects it.
  • Assuming a normal stop reason guarantees exact enum capitalization.

Where the exam guide differs

Note:

The guide describes “guaranteed schema-compliant structured output” through tool use. Anthropic’s documentation qualifies that guarantee with unsupported schema features, refusals, truncation, and string enum or const casing variants. The guide also presents any and named forcing without the model and manual-thinking restrictions documented by the product. Read an exam item about structural reliability as a comparison of strict schema enforcement with prompt-only formatting; do not infer that every response is an accepted record or that every model accepts forced selection.

What to remember

Inspect request errors, stop_reason, and the expected content blocks before consuming a record. Repair the rejected contract, address refusal causes, increase a truncating budget, or change the selection guarantee according to the failure. Structural success then leads to semantic validation.

Knowledge check

References