- In short
- Appending a Claude tool result means adding a new user-role message whose content includes a tool_result block carrying the tool_use_id from the model's request and the tool's output. This lets the model reason about what the tool returned on the next turn of the agentic loop.
What appending a tool result means
After Claude returns a tool_use block, the ball is in your court: you run the requested function and you have to tell the model what happened. Appending a Claude tool result is how you do that. You construct a new message with role user, and inside its content you place a tool_result block holding the output your function produced. Then you resend the whole conversation, and on the next turn the model can finally reason about the data it asked for.
The mechanics are precise because the model needs to line up each answer with the question that prompted it. That alignment is carried by the tool_use_id. This knowledge point is rated at the apply level on the Claude Certified Architect exam for a reason: you are not just recognising the pattern, you are expected to assemble the message correctly under scenario pressure.
- tool_result block
- A content block, placed inside a user-role message, that returns the output of a tool Claude requested. It references the originating tool_use_id and carries the tool's content so the model can use it on the next turn.
The anatomy of the appended message
Three things have to be true for the append to work. First, the message you add has role user, counter-intuitively, tool results travel back as user content even though no human typed them. Second, its content is an array of blocks, and at least one block has type: "tool_result". Third, that tool_result names the tool_use_id it answers.
role: "user", tool results are delivered on a user turn, immediately after the assistant's tool_use turn.type: "tool_result", the block type the model recognises as the answer to a tool call.tool_use_id, the exact id from the model'stool_userequest, so results pair with calls.content, the output itself, typically the stringified or structured return value of your function.
A subtlety the Anthropic documentation calls out: when a user message carries tool results, the tool_result blocks should come first in the content array, before any accompanying text. Getting the ordering and the id right is what keeps a multi-tool turn unambiguous.
Why results travel on a user turn
It surprises many developers that a tool result is delivered on a message with role user, even though no person typed it. The reason follows directly from the request-response cycle: the model produced the tool_use request on its assistant turn, so the next turn, the one that supplies what the model asked for, is, by the alternating-roles convention, a user turn. The user role here means "input to the model," not "a human." Your application is acting on the user's behalf, feeding the requested data back in.
Holding that mental model straight prevents a class of formatting errors. If you try to return tool output as an assistant message, or interleave a fresh assistant turn between the tool_use and the tool_result, the transcript stops alternating cleanly and the request becomes malformed. The rhythm is fixed: assistant requests a tool, user returns the result, assistant reasons about it, and so on until the model is done.
Stringifying output and signalling errors
Tools return all kinds of data, JSON objects, numbers, plain strings, but the content of a tool_result is ultimately text the model reads. In practice you serialise structured output (for example, stringify a JSON object) and place it in the block's content. Keeping that serialised output clean and high-signal matters: bloated or noisy tool output wastes context and makes it harder for the model to extract what it needs on the next turn.
There is also a dedicated way to report failure. When a tool errors, you can set is_error: true on the tool_result block and put a short description of what went wrong in the content. This tells the model the call failed rather than succeeded, so it can retry, choose a different tool, or explain the problem to the user. Silently returning an empty or misleading result instead of flagging the error is a common mistake that leaves the model reasoning on bad data. Returning a clear, structured error keeps the loop honest and is the foundation that later normalisation and error-handling knowledge points build on.
Why the history must include the assistant's tool_use turn
A frequent and costly mistake is appending the tool_result without first appending the assistant message that requested it. Remember from the request-response cycle that the API is stateless. The model does not remember asking for a tool; it only knows what is in the history you send. So your sequence must be: the assistant message containing the tool_use block, then the user message containing the matching tool_result.
If you skip the assistant turn and jump straight to a tool_result, you hand the model an answer to a question it has no record of asking. The conversation no longer reads as a coherent transcript, and the request is malformed. The fix is always the same: preserve the assistant's tool_use turn in the history, then append the result right after it.
Matching ids when the model calls several tools at once
The model can request multiple tools in a single turn, emitting several tool_use blocks each with its own id. When that happens, you run all of them and return all of their results in one user message, one tool_result block per call, each referencing its own tool_use_id. The ids are what let the model match three results to three calls without confusion.
This is where careless code goes wrong: developers loop over the tool calls, run them, and accidentally attach every result to the same id, or return them in a separate message each. The model then cannot reliably reconstruct which output answers which request. Treat the ids as a join key. One call, one id, one result that names that id.
A practical implication is that you should gather all the results before sending anything back. If the model requested three tools, you run all three, build one user message containing three tool_result blocks, and send that single message. Resist the urge to fire off each result as it completes; splitting them across messages breaks the alternation the API expects and scatters the join keys across turns. Collect, assemble, send once, then read the next response and repeat.
Worked example: an order-lookup support agent
Worked example
A support agent must check an order status before replying. The model requests a get_order tool, and your code returns the result.
The customer asks, "Where is order 5582?" You send the history with a get_order tool defined. Claude responds with a tool_use block, name: "get_order", input: { order_id: "5582" }, id: "toolu_88", and a stop_reason of tool_use.
Your code runs get_order("5582") and gets back { status: "shipped", eta: "Friday" }. Now you append. You keep the original user question, keep the assistant message with toolu_88, and add a new user message whose content is a single tool_result block: tool_use_id: "toolu_88", content set to the order JSON. You resend the entire list.
On the next turn the model sees the shipped status paired to its own request and writes the final reply: "Order 5582 shipped and should arrive Friday." Had you appended the result without referencing toolu_88, or without the assistant turn in between, the model would have had a dangling answer and the loop would have stalled.
Notice how little the model has to do for this to work and how much your code carries. The model named the tool, supplied the input, and tagged the request with an id. Everything else, running the function, wrapping the output in a tool_result that echoes that id, ordering the message correctly, and resending the full transcript, is your responsibility. The append is the seam between the model's intent and the real world, and getting that seam exactly right is what makes the difference between a working agent and one that quietly drops half its work.
Mistakes that quietly break the loop
The two errors below are exactly the kind the exam dramatises in a debugging scenario. Both produce an agent that behaves oddly rather than crashing outright, which is what makes them worth memorising.
Misconception
I can send the tool's output back as a plain text user message and Claude will figure it out.
What's actually true
Misconception
I only need to append the tool_result; the assistant's tool_use turn can be dropped to save tokens.
What's actually true
How appending sustains the agentic loop
Appending is not a one-off step; it is the heartbeat of a multi-turn agent. Each cycle, the model may ask for another tool, and each time your code runs it and appends the result before sending the history again. The conversation grows by two messages per tool round, the assistant's request and the user's result, and the model reasons over the whole accumulated transcript each time. This is how an agent chains several tool calls together to complete a task that no single call could finish.
That growth is also why correctness compounds. A single mis-formed append does not just break one turn; it can derail every subsequent turn, because the malformed history is resent on every later call. Treating the append as a precise, repeatable operation, right role, right block type, right id, right ordering, is what lets an agent run ten tool-using turns as reliably as it runs one. The discipline you apply on turn one is the discipline that holds the loop together at turn ten.
How this is tested on the exam
Task 1.1 questions love to present a snippet of broken agent behaviour: a tool runs but the model ignores the result, or an agent with several tools mixes up which answer goes where. The diagnosis is almost always a tool-result-appending error, a missing tool_use_id, a dropped assistant turn, results returned in separate messages, or an error that was never flagged with is_error. Because this knowledge point unlocks debugging premature loop termination, getting fluent with the correct append shape pays off across multiple later questions. Build the message right and the loop continues; get the id wrong and the whole agent stumbles.
Claude requests two tools in one turn, toolu_A and toolu_B, and your code executes both. How should you return the results so the model can continue correctly?
People also ask
How do I send a tool result back to Claude?
Where do tool_result blocks go in the message array?
What happens if the tool_use_id does not match?
Watch and learn
Official Anthropic Academy lessons first, then hand-picked walkthroughs. Videos load only when you press play.
Sending tool results
Why watch: Demonstrates appending tool_result blocks that reference the originating tool_use_id, the precise mechanic this KP defines.
More videos for this concept
References & primary sources
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.