Structured outputs let you pin Claude's response to a JSON Schema: pass output_config: {"format": {"type": "json_schema", "schema": {...}}} and the API constrains generation so the output conforms. Teams reasonably read that as "parsing can never fail." It can — in one specific, documented way. The max_tokens parameter is a hard ceiling on how many tokens the model may generate, and when generation hits that ceiling mid-object, the API returns HTTP 200 with stop_reason: "max_tokens" and whatever JSON had been produced so far. A truncated object is missing closing braces, required fields, or half a string value, so it fails both JSON parsing and schema validation.
Why "repair" is the wrong instinct
The tempting fix is to patch the fragment — append closing braces, drop the last incomplete field, fill required keys with nulls. Anthropic's documentation is explicit that the correct handling is different: output cut off by max_tokens may be incomplete or invalid, so retry the request with a higher max_tokens value. The reasons hold up under scrutiny:
You cannot tell what is missing. A truncated array might have contained two more elements; a truncated string might have ended mid-sentence in a way that inverts its meaning. Syntactic repair produces something parseable, not something correct.
The schema guarantee only covers completed generations. The constrained decoding that makes structured outputs work steers the model token by token toward a valid document. Cutting that process short leaves you outside the guarantee, and downstream code that assumes "schema-valid" is now consuming fabricated defaults.
Check stop_reason before you parse
The robust pattern is to branch on stop_reason before touching content:
| stop_reason | Meaning | Action |
|---|---|---|
end_turn | Generation completed normally | Parse and validate as usual |
max_tokens | Hit the token ceiling mid-output | Retry with a larger max_tokens |
refusal | Model declined the request (still HTTP 200, still billed) | Handle separately — output may not match the schema |
from anthropic import Anthropic
client = Anthropic()
max_tokens = 1024
for _ in range(3):
msg = client.messages.create(
model="claude-sonnet-5",
max_tokens=max_tokens,
output_config={"format": {"type": "json_schema", "schema": SCHEMA}},
messages=[{"role": "user", "content": prompt}],
)
if msg.stop_reason != "max_tokens":
break
max_tokens *= 2 # truncated JSON: retry larger, never repair
The Python SDK's client.messages.parse() helper (with Pydantic models) validates the response client-side as well, which turns a silently truncated object into a loud failure — exactly what you want. Refusals deserve their own branch; see the refusal stop_reason article.
The thinking-token trap
On models with thinking enabled, max_tokens caps thinking plus response text combined. A budget that comfortably fits your largest expected JSON document can still truncate it if the model spends most of the budget reasoning first. If structured-output truncation appears on requests where the JSON itself is small, the fix is the same retry-with-more-headroom, or a lower effort setting to shrink thinking. The thinking/max_tokens trap covers this interaction in depth.
stop_reason: "max_tokens" on a structured-output request as a retryable capacity error in your own application logic — same shape as a 429, except the parameter you raise is max_tokens. One nuance: max_tokens has no rate-limit downside, because OTPM counts only tokens actually generated. Setting it generously costs nothing until the model actually uses it.Structured outputs work with streaming too, but the same rule applies: you cannot validate until the final event arrives, so buffer the fragments and check the stop_reason delivered in message_delta before parsing.
Where to go next
For the feature itself — supported schemas, strict tool use, and platform availability — start with the structured outputs overview, or browse the feature matrix.