HANDOFF
Reporting on autonomous software

Truncated tool call: a 200 OK that cut the arguments off mid-JSON

An agent tool call truncated by max_tokens arrives as HTTP 200 with incomplete JSON. Which stop reason to check on Claude and OpenAI, and how to retry.

Reported figures
200
Anthropic's stop reasons documentation, read 15 October 2026, states that stop_reason is part of every successful response and that 4xx and 5xx HTTP errors are distinct from stop reasons, so a max_tokens stop arrives as HTTP 200. It says an incomplete tool use block must be retried with a higher max_tokens. Not our measurement.
By , Handoff Published 6 min read

Key takeaways

  • A tool call cut off by the output limit returns HTTP 200. On the Claude API the signal is stop_reason: max_tokens with a tool_use block as the last content block; on OpenAI's Responses API it is status: incomplete with reason max_output_tokens.
  • Anthropic's documentation says a response with an incomplete tool_use block must be retried with a higher max_tokens to get the full tool use. Repairing the JSON by hand can produce a valid call with missing arguments.
  • Current Claude models allow up to 128K output tokens per synchronous request, so a low max_tokens set in a prototype, not the model, is the usual ceiling.
  • Not every 'length' stop is a length stop. Hermes Agent issue #26425 traced false truncations to dropped streams being converted into a synthetic finish_reason length; the fix raised truncation retries from 1 to 3 with growing limits.
  • Check the stop reason before parsing tool arguments, on every response. A schema validator alone cannot tell a cut-off call from a complete one when the cut lands between fields.

Cut off by the output limit, a tool call does not fail. Anthropic’s stop reasons documentation puts stop_reason in every successful Claude API response and keeps 4xx and 5xx errors apart, so a cut-off call arrives as HTTP 200. The truncation is one field in the body, and a loop that does not read it passes half a JSON object to the parser.

What happens next depends on the parser. Some throw. Some repair the JSON, and then the agent executes a call with arguments that were never finished.

What does a truncated tool call look like?

Like a normal response with one field set differently. The two largest APIs mark it in different places.

How truncation by the output limit is reported, by API. Sources: Anthropic stop reasons, models overview and context windows documentation; OpenAI structured outputs guide and openai-python SDK types; all read 13 October 2026.
APIHTTP statusField to checkValue meaning truncatedMax output per request
Claude Messages API200stop_reasonmax_tokens128,000 tokens
Claude Messages API200stop_reasonmodel_context_window_exceededBounded by 1M context window
OpenAI Responses API200status, incomplete_details.reasonincomplete, max_output_tokensModel-specific
OpenAI Chat Completions200finish_reasonlengthModel-specific

The Claude case to watch is max_tokens with a tool_use block as the last content block. Anthropic’s documentation says such a response needs a retry with a higher max_tokens to get the full tool use; the partial block does not carry the complete input.

Why does truncation hit tool calls in particular?

Because tool arguments are often the longest thing the model writes in a turn. A tool that writes a file, sends a document or posts a long message carries its whole payload in the arguments. A max_tokens value that comfortably fits a chat answer can end in the middle of a file body.

The ceiling is rarely the model. Current Claude models allow up to 128,000 output tokens per synchronous request, according to Anthropic’s models overview re-checked on 15 October 2026. The usual ceiling is a value someone set while prototyping. Aggregating finish reasons from your traces is the quickest way to see how many runs that old value is cutting off.

A second cause sits at the other end of the window. If input plus output fills the model’s context window first, Claude stops with model_context_window_exceeded instead. Anthropic says to treat that as truncated too. Raising max_tokens will not help there; the input has to shrink.

Why not repair the JSON and carry on?

Because a repaired call can be valid and wrong.

When the cut lands mid-string, a repair closes the string and the object. The call now parses, passes the schema, and writes half a file. When the cut lands between fields, the result can be a complete object with a required field missing, or an optional one silently absent. This is the same gap as a call whose schema passed and whose values were wrong, produced by the loop rather than the model.

Anthropic’s guidance is direct: retry the request with a higher max_tokens to get the full tool use. OpenAI’s structured outputs guide checks for an incomplete status before parsing and treats it as an error.

Was it really the output limit?

Not always, and a wrong diagnosis sends the retry in the wrong direction.

Hermes Agent issue #26425, opened on 15 May 2026, reported truncation errors across several models and providers. The maintainers traced part of it to streams that dropped mid-response being converted into a synthetic finish_reason of length. A network stall was being reported as an output cap. The fix, in PR #36705, separated network interruptions from real truncation, raised tool-call truncation retries from 1 to 3 with progressively larger output limits, and kept the request’s original cap as a floor so a high default was not lowered to 8K or 12K.

The lesson for any loop: a length stop from a stream that ended early is a network failure. Retry it as one, not by raising the limit.

Three causes of a cut-off tool call, the signal that separates them and the retry each needs. Sources: Anthropic stop reasons and context windows documentation; Hermes Agent issue #26425. The retry column is our editorial judgement.
CauseSignalRetry that helpsRetry that does not
Output limit reachedstop_reason max_tokens, or finish_reason length on a complete streamSame request, higher max_tokensRepairing the JSON
Context window fullstop_reason model_context_window_exceededSmaller input: clear old tool results, compactHigher max_tokens
Stream droppedNo final stream event; client may synthesise a length stopSame request, same limit, network backoffHigher max_tokens

What should the loop check, and in what order?

Our recommended order, which is editorial judgement built on the provider guidance above:

  1. Read the stop reason before touching content. On Claude, max_tokens or model_context_window_exceeded; on OpenAI, incomplete or length.
  2. If the last block is a tool call, do not execute it. Not partially, not after repair.
  3. Check the stream ended cleanly. A stream without its final event is a network failure, not a length stop.
  4. Retry with a higher output limit, a bounded number of times. Hermes Agent settled on 3 attempts; set a ceiling below the model’s 128,000-token maximum that you are willing to pay for.
  5. If the payload is genuinely large, change the tool. Write in chunks or pass a reference to stored content instead of the content itself.

The question for the loop’s owner: when was max_tokens last changed, and does the code read stop_reason before it parses a single argument?

Frequently asked questions

Why does my agent's tool call have incomplete JSON?

Most often because the response hit the max_tokens limit while the model was writing the tool arguments. The API returns HTTP 200 and marks the stop reason, so the loop must check it before parsing.

What should I do when stop_reason is max_tokens during tool use?

Anthropic's documentation says to retry the request with a higher max_tokens to get the full tool use. Do not execute the partial call.

How do I detect truncation on the OpenAI Responses API?

Check whether response.status is incomplete and incomplete_details.reason is max_output_tokens. OpenAI's structured outputs guide uses that condition before parsing JSON.

What is model_context_window_exceeded?

A Claude stop reason meaning generation stopped because input plus output filled the model's context window, not your max_tokens. Anthropic says to treat it as a truncated response.

Can a network drop look like a max_tokens truncation?

Yes, in some clients. Hermes Agent found that streams dropped mid-response were being converted into a synthetic length stop, which triggered the wrong retry logic.

Method and sources

  1. Anthropic, Handling stop reasons, Claude API documentation, read 13 and re-checked 15 October 2026. Source of the 7 stop reason values, the guidance on incomplete tool_use blocks at max_tokens, model_context_window_exceeded, and the statements that stop_reason is part of every successful response and that 4xx and 5xx errors are distinct from stop reasons.
  2. Anthropic, Models overview and Context windows, read 13 and re-checked 15 October 2026. Source of the 128K maximum output per synchronous request, the 1M-token context windows and the overflow behaviour.
  3. OpenAI, Structured outputs guide, read 13 October 2026. Source of the status incomplete and incomplete_details.reason max_output_tokens check.
  4. OpenAI, openai-python SDK, src/openai/types/chat/chat_completion.py, read 13 October 2026. Source of the Chat Completions finish_reason value length, documented as the maximum number of tokens specified in the request being reached.
  5. NousResearch, hermes-agent issue #26425, opened 15 May 2026, fixed in PR #36705. Source of the synthetic finish_reason length from dropped streams and the change from 1 to 3 truncation retries with growing max_tokens.
  6. The order of checks in the last section and the retry ceiling are our editorial judgement. We ran no truncation experiment of our own.
TD

, Handoff at Handoff

The Tooling desk of Handoff. Every figure here carries a source, a sample size and a date, and we say plainly what we have not measured ourselves.