
Why the Model Response Got Cut Off (stop_reason: max_tokens)
Figures on this page were verified 31 August 2026 against the providers' own documentation. Pricing, context windows and rate limits change without notice, so confirm any number against the provider before you rely on it. Tell us if something here is out of date.
If the reply stops mid-sentence, the model did not fail and nothing errored. It hit the output ceiling you set. The response comes back HTTP 200 with a stop reason telling you exactly that, and because it is a success rather than an exception, most code paths never notice. Check the stop reason on every call.
The field to check
| Provider | Field | Truncated value | Normal value |
|---|---|---|---|
| Anthropic | stop_reason | max_tokens | end_turn |
| OpenAI | finish_reason | length | stop |
resp = client.messages.create(
model="claude-opus-5",
max_tokens=1024,
messages=[{"role": "user", "content": prompt}],
)
if resp.stop_reason == "max_tokens":
# The text is incomplete. Do not parse it as if it were whole.
handle_truncation(resp)This matters most when the output feeds something else. Truncated JSON fails to parse, truncated code fails to compile, and a truncated summary silently loses its conclusion. A 200 response is not a guarantee of a complete one.
Why it happens
- max_tokens is simply too low for what you asked. A request for a detailed breakdown will not fit in 256 tokens.
- Reasoning consumed the budget. On models that think before answering, that thinking is billed and counted as output. A generous-looking ceiling can be spent before the visible answer starts.
- The prompt invited length without you noticing. “Explain in detail” and “list every” produce exactly what they ask for.
Fixing it
Raise the ceiling, within reason
The obvious fix, but do not simply set it to the model maximum. Reserved output counts against the context window and against your tokens-per-minute rate limit, so an inflated max_tokens costs you headroom on both even when the reply is short. Set it from the job.
Ask for less instead
Constraining the output in the prompt is usually better than raising the limit. “Answer in under 150 words”, “return only the JSON object”, or “give three bullet points” produce shorter completions that cost less and truncate less. Since output tokens are priced several times higher than input, this is the cheapest lever available.
Stream long outputs
Large non-streaming requests risk HTTP timeouts as well as truncation. Streaming avoids the timeout and lets you display partial output while it arrives. SDKs generally require streaming above a certain output size for exactly this reason.
Continue, do not restart
If a long generation truncates, sending the same prompt again costs the same input tokens and may truncate at the same point. Send the partial output back and ask the model to continue from it. You pay for the partial text again as input, which is cheap, rather than regenerating everything at output rates.
Structured output is the case that bites
Truncated prose is merely unhelpful. Truncated JSON is a crash. If you are parsing model output, treat a truncation stop reason as a hard failure before you reach the parser, otherwise your traceback will point at the JSON decoder and hide the real cause.
if resp.stop_reason == "max_tokens":
raise TruncatedOutput("raise max_tokens or shorten the schema")
data = json.loads(resp.content[0].text) # only now is this safeWhere the provider supports constrained or structured output, use it. Guaranteeing the shape of the response removes a whole category of parsing failure, though it does not remove the need to check the stop reason.
Related
Reserved output tokens also count toward the context window, which is the other half of context_length_exceeded, and toward your token-per-minute budget in 429 rate limits. To see what output length actually costs, try the LLM API cost calculator. Our context budget planner shows how much of the window your fixed overhead consumes and at which turn a conversation breaks.
This page is part of our LLM API error reference, which covers every common error across OpenAI and Anthropic and whether each one is safe to retry.
Frequently asked questions
Is a truncated response an error?
No, and that is what makes it dangerous. The call returns HTTP 200. The only signal is stop_reason set to max_tokens on Anthropic, or finish_reason set to length on OpenAI. Code that checks status codes alone will treat a half-finished answer as a success.
How do I detect truncation reliably?
Check the stop reason on every response before you use the content. Do not infer completeness from whether the text reads as finished, and do not treat successfully parsed JSON as proof, because JSON can be cut at a point where it still parses.
How do I get the rest of the answer?
Raise max_tokens if the context window has room, ask for a shorter answer, split the task into smaller calls, or continue the generation by sending the partial output back and asking the model to resume from where it stopped.


