AI Skill Certs
Agentic Architecture & Orchestration·Task 1.1·Bloom: understand·Difficulty 2/5·7 min read·Updated 2026-06-07

stop_reason Field Inspection: Controlling the Agentic Loop

Design and implement agentic loops for autonomous task execution

SUBy Solomon UdohReviewed by Solomon UdohAI-assisted · human-reviewed
In short
stop_reason is a field on every Claude Messages API response that tells your code why the model stopped generating. tool_use means Claude wants to call a tool, so your agent loop should continue; end_turn means Claude has finished, so the loop should stop.

What stop_reason actually is

Every response from the Claude Messages API includes a top-level stop_reason field. It is Claude's structured answer to a single question: why did I stop generating just now? For anyone building an agentic loop, this field is the steering wheel. It is how your code knows whether to hand control back to the user, run a tool and loop again, or recover from a truncated response.

The reason this matters is that an agent is not one request. It is a loop. You send a message, Claude responds, and your code has to decide what happens next based on that response. stop_reason is the machine-readable instruction that drives that decision, every single turn.

stop_reason
A field on every Messages API response indicating why generation halted. The values an agent loop cares about most are tool_use (Claude is requesting a tool call) and end_turn (Claude has finished its turn).

The values you need to know

For the exam and for real systems, focus on these:

  • end_turn. Claude finished naturally. The loop should stop and the final text is ready for the user.
  • tool_use. Claude emitted one or more tool_use content blocks and is waiting for results. The loop should execute the tools, append the results, and call the API again.
  • max_tokens, generation hit the max_tokens ceiling and was cut off. The response is incomplete; you may need to continue or raise the limit.
  • stop_sequence, a custom stop sequence you supplied was produced.
tool_use
continue the loop
end_turn
stop the loop
max_tokens
handle truncation

How it controls the agentic loop

The canonical agent loop is a while loop gated on stop_reason. Conceptually: keep calling the model as long as it keeps asking for tools, and break the moment it says it is done.

The stop_reason-driven agent loop
Loading diagram...
The loop branches entirely on the structured stop_reason field, never on the model's prose.

The key insight is that the branch condition is structured data, not language. You check response.stop_reason === "tool_use", you do not read the assistant's sentence and guess.

It is worth dwelling on why this loop is the canonical shape rather than one option among many. An agent is, by definition, a system that keeps acting until its work is done, and the only reliable per-turn signal of "keep acting versus done" is stop_reason. Anchoring the loop on that field means the loop's length is decided by the task itself: a one-shot question exits after a single turn, while a multi-step task runs as many tool-using turns as it genuinely needs. The structure adapts to the work because the stopping condition reflects the model's real intent on each turn, not a guess or a fixed count. That adaptivity is exactly why the field, and the loop built on it, sit at the foundation of the entire agentic-architecture domain.

Worked example

A support agent must look up an order, then answer the customer. You send the user's question along with a get_order tool.

On the first turn, Claude cannot answer without the order data, so it returns a tool_use block requesting get_order and a stop_reason of tool_use. Your loop sees tool_use, runs the function, and appends a tool_result block with the order JSON.

On the second turn, Claude now has everything it needs. It writes the final reply to the customer and returns stop_reason: end_turn. Your loop sees end_turn, breaks, and sends that text to the user. Two turns, one loop, and every branch decided by the field, not by reading Claude's wording.

Why you must not parse the prose

A tempting shortcut is to inspect the assistant's text, "if it says let me look that up, it probably wants a tool." This is the classic anti-pattern, and it is brittle for three reasons:

  1. Natural language is ambiguous. Claude might narrate its reasoning without actually emitting a tool call, or call a tool without narrating at all.
  2. It does not localise or version well. Phrasing changes across prompts and model versions; the stop_reason contract does not.
  3. It hides the real signal. The structured field already tells you exactly what happened. Re-deriving it from text throws away a guarantee and replaces it with a heuristic.

Misconception

If Claude's reply mentions calling a tool, that means it issued a tool call.

What's actually true

Whether a tool was actually requested is determined by stop_reason === 'tool_use' and the presence of tool_use content blocks, not by the wording of the text. Always branch on the structured field.

Don't forget max_tokens

A subtle exam trap is treating the loop as a binary: continue on tool_use, stop on everything else. But max_tokens is neither a clean finish nor a tool request. It means Claude was cut off mid-thought. If you treat it as end_turn, you ship a truncated answer. Handle it explicitly: either raise max_tokens, or send a follow-up turn asking Claude to continue.

There is an even sharper edge to this when tools are involved. If a response hits max_tokens while in the middle of emitting a tool_use block, that tool request is itself incomplete and cannot be safely executed. The documented remedy is to retry the request with a higher max_tokens so the model can finish the tool call cleanly. Lumping max_tokens in with the finished case does not just truncate prose; it can hand your code a half-formed tool invocation, which is a far nastier failure. Every value the field can take is its own instruction, and the ones an agent forgets to handle are precisely where production breaks.

Treat stop_reason as an exhaustive switch, not an if/else. Every value is a different instruction, and the ones you forget to handle are exactly where production agents break.

Misconception

Any stop_reason other than 'tool_use' means the response is finished and safe to return to the user.

What's actually true

Only end_turn (and a deliberately configured stop_sequence) signals a clean finish. max_tokens means the output was truncated mid-generation, and pause_turn and refusal each need their own handling. Treat stop_reason as an exhaustive switch with a branch per value, not a 'tool_use versus everything else' binary that surfaces truncated or refused turns as complete answers.
Check your understanding

Your agent loop continues whenever stop_reason is 'tool_use' and otherwise returns the assistant text to the user. In testing, some answers come back oddly truncated. What is the most likely cause?

Where the field lives in the response

A small but important detail is that stop_reason sits at the top level of the response object, beside the content array and the usage block, not inside any individual content block. It is the response's summary verdict on why generation halted, computed once for the whole turn. That placement is a hint about how to use it: you read it once per response to decide what your loop does next, rather than scanning through content blocks hoping to infer the model's intent.

Because the Messages API is stateless, this verdict is also strictly per-response. Each call computes its own stop_reason for that turn alone; nothing carries over from a previous request. So in an agentic loop you check the field fresh on every iteration, and each check governs only that iteration's branch. There is no cumulative or remembered stop state to reason about, just one clean signal, recomputed every turn.

The fuller set of values

Beyond the four everyday outcomes, the API defines additional values that a thorough agent should handle. pause_turn appears when a server-side tool loop, such as web search, reaches its iteration limit mid-turn; the documented response is to send the assistant's reply back unchanged so the model can continue where it left off. refusal indicates the model declined to generate for safety reasons, which your application should surface or handle deliberately rather than blindly retry; on newer models (Opus 4.7 and later) a refusal also carries a stop_details object naming the policy category, so a careful handler can branch on why the model declined instead of treating every refusal alike. Newer models also expose model_context_window_exceeded, signalling the response hit the context window rather than your max_tokens.

You do not need to memorise every value's edge cases for the foundations exam, but you should know that stop_reason is an extensible, exhaustive signal, not a two-way switch. The robust pattern is a branch per value, with a sensible default, rather than an if tool_use / else binary that silently lumps truncation, pauses, and refusals together with a clean finish. Treating the field as a complete switch is what separates an agent that handles the real world from one that only handles the happy path.

Branch on structured data, never on language

The throughline of this knowledge point is a single discipline: decide loop control from structured data, not from prose. Your code asks response.stop_reason, it does not read the assistant's sentence and guess. This matters because the structured contract is stable while language is not, wording shifts across prompts and model versions, but a turn that wants a tool always reports tool_use. Building on the wording is building on sand; building on the field is building on the API's guarantee.

This principle is the seed of the agentic loop anti-patterns knowledge point, where each anti-pattern is, at root, a different way of substituting a proxy for stop_reason. It also underlies debugging premature loop termination, where reading a content block's type instead of the stop field ends loops early. Once you internalise "branch on the field, not the prose," a whole cluster of later Domain 1 problems becomes predictable rather than surprising.

A subtle trap: empty turns after tool results

One quirk the documentation calls out is worth filing away. Sometimes Claude returns an almost-empty response with stop_reason: end_turn, often right after tool results, because it has interpreted the turn as already complete. A common trigger is adding a stray text block immediately after a tool_result, which teaches the model to expect the user to always speak after tool results, so it ends its own turn to fit the pattern. The fix is to return tool results cleanly, without appending unnecessary text, and to use an explicit continuation prompt only as a last resort.

The lesson generalises: stop_reason faithfully reports the model's decision, but that decision is shaped by the exact shape of the history you send. So when an agent stops in a way that puzzles you, the answer is rarely to fight the field. It is to look at how the conversation was assembled. The field is the messenger; the history is the message.

How this is tested on the exam

Domain 1 (Agentic Architecture & Orchestration) is the heaviest on the exam, and Task 1.1, designing agentic loops, leans directly on this concept. Expect scenario questions that describe a loop misbehaving (infinite looping, premature stopping, truncated output) and ask you to identify the cause in terms of stop_reason handling. Mastering the field, its values, and the branch-on-structured-data principle is foundational to nearly everything else in the domain.

People also ask

Does stop_reason persist across API requests?
No. The Messages API is stateless, so every request returns its own stop_reason for that response only.
What are the possible stop_reason values?
Commonly end_turn, tool_use, max_tokens, and stop_sequence, plus pause_turn and refusal on newer models. Agent loops branch primarily on tool_use versus everything else.
Should I keep looping while stop_reason is end_turn?
No, end_turn means Claude is finished. You continue the loop on tool_use; end_turn is the signal to stop and return the answer.

Watch and learn

Official Anthropic Academy lessons first, then hand-picked walkthroughs. Videos load only when you press play.

Official · Anthropic AcademyOpen full lesson in Academy

Introducing tool use

Why watch: Introduces how Claude signals it wants to act via stop_reason tool_use, the signal this KP uses to decide whether to keep looping.

More videos for this concept

References & primary sources

Adaptive study

Master this concept with Archie

Practice it inside an adaptive study session. Archie, your Socratic AI tutor, tracks your mastery with Bayesian Knowledge Tracing and schedules the perfect next review.

Start studying