Figures on this page were verified 18 October 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.
A tool-use turn that stops early is usually hitting one of four specific ceilings, and only one of them is an error: the rest are normal stop reasons that your loop has to handle. The most commonly missed is pause_turn, which looks like a response that simply ended mid-task but is actually Anthropic asking you to continue.
This page covers the limits we have verified against Anthropic’s documentation. We have not verified an equivalent per-turn ceiling on OpenAI’s function-calling API, so we do not list one rather than guess.
The four ceilings
| Signal | What hit the limit | Is it an error? | What to do |
|---|---|---|---|
stop_reason: "pause_turn" | Server-side tool loop reached 10 iterations | No | Send the response back as-is to continue |
stop_reason: "max_tokens" ending on a tool_use block | Output ceiling hit mid-call | No, but the call is incomplete | Retry with a higher max_tokens |
stop_reason: "model_context_window_exceeded" | The context window filled | No | Treat the response as truncated |
| 400 “Schema is too complex for compilation” | Strict-mode schema ceilings | Yes | See strict schema rejections |
pause_turn: the one everybody misses
When Claude runs a server tool such as web search, the sampling loop runs on Anthropic’s side. That loop has an iteration limit, and the default is 10 iterations per request. If it is reached before the task finishes, the response returns stop_reason: "pause_turn" and may contain a server_tool_use block with no matching result. That is not a failure. It is the API handing control back so you can decide whether to continue.
The documented fix is to send the response back unchanged and let the model pick up where it stopped. Anthropic also tells you to handle pause_turn in any agent loop that uses server tools, which is the instruction most code skips.
MAX_CONTINUATIONS = 5 # your own safety cap, not an API limit
messages = [{"role": "user", "content": user_query}]
response = client.messages.create(model=MODEL, max_tokens=4096,
messages=messages, tools=tools)
for _ in range(MAX_CONTINUATIONS):
if response.stop_reason != "pause_turn":
break
# replace the full message list so roles keep alternating
messages = [
{"role": "user", "content": user_query},
{"role": "assistant", "content": response.content},
]
response = client.messages.create(model=MODEL, max_tokens=4096,
messages=messages, tools=tools)Note the cap of five continuations. That number is a choice in the example, not something the API enforces, and you should treat it as your own protection against an unbounded loop, for the cost reasons set out in tool-use loops.
Two details that cause real bugs. A response waiting on your client tools never uses pause_turn; it is always tool_use. And if you resume without including the server tool in your tools array, the request fails with a 400 whose message ends “but no web_search tool was provided”.
max_tokens in the middle of a tool call
If stop_reason is max_tokens and the last content block is a tool_use block, the tool call was cut off partway through its arguments and is incomplete. Do not run it. Retry the same request with a higher limit.
last = response.content[-1]
if response.stop_reason == "max_tokens" and last.type == "tool_use":
# arguments are partial; running this would act on half a call
response = client.messages.create(model=MODEL, max_tokens=4096, # was 1024
messages=messages, tools=tools)This is the same failure covered in tool call arguments that will not parse, seen from the limit side. The general case is in why the response got cut off.
model_context_window_exceeded
This stop reason means the response filled the model’s context window. It exists so you can request a large max_tokens without having to know the input size in advance, and it should be treated as a truncated response rather than a complete one. Sonnet 4.5 and newer return it without a beta header; earlier models need the model-context-window-exceeded-2025-08-26 beta header. In tool loops it is the failure that eventually arrives if nothing else stops the conversation, because every tool result grows the history. The arithmetic is in context_length_exceeded.
Web search has its own use limit
Server tools report their own errors in-band rather than as HTTP failures. The web search tool can return the error code max_uses_exceeded when its configured maximum number of searches is reached, alongside too_many_requests, invalid_input, query_too_long and unavailable. Unlike client tools, you do not need to handle is_error for these; Claude handles them and tries to give an alternative answer.
What no provider enforces for you
The ceilings above all concern what a single response or a server-side loop may do. How many turns your client-side tool loop runs, and how many times the same tool is called, is entirely your code. The Messages API is stateless between requests, so nothing carries a count across calls except what you send. A loop with no cap of its own is the usual cause of a runaway bill, and it is the one limit you must build yourself.
A single handler for all of it
def classify(response):
reason = response.stop_reason
last = response.content[-1] if response.content else None
if reason == "end_turn":
return "done"
if reason == "tool_use":
return "run_client_tools" # return one result per tool_use block
if reason == "pause_turn":
return "continue_as_is" # server loop hit its iteration limit
if reason == "max_tokens" and last is not None and last.type == "tool_use":
return "retry_with_higher_max_tokens" # incomplete tool call, do not run it
if reason == "max_tokens":
return "truncated_text"
if reason == "model_context_window_exceeded":
return "truncated_context"
return "unexpected" # log it, do not guessThe last line matters. A new stop reason should land in a branch that logs loudly rather than falling through to a default that treats it as success.
Related errors
For loops that run too long because nothing stops them, see tool-use loops. For results that go missing when several tools run at once, see parallel tool calls and how they fail. The full map is in the LLM API error reference.
Frequently asked questions
What does stop_reason pause_turn mean?
A server tool such as web search reached the default limit of 10 iterations in one request. It is not an error: send the response back as-is to continue, and handle it in any agent loop that uses server tools.
What if max_tokens cuts off a tool call?
If stop_reason is max_tokens and the last block is tool_use, the call is incomplete. Do not run it; retry the request with a higher max_tokens.
Who enforces a cap on my client-side tool loop?
You do. The Messages API is stateless between requests, so a limit on turns or repeated calls has to be built into your own loop.



