F2.4 F2

Sending Tool Results Back: The tool_result Block

After your code executes a tool, you send the result back to Claude through the normal Messages API — not a special endpoint, not a callback, just another message in the conversation.

The linking field: tool_use_id

The tool_result block must include a tool_use_id that exactly matches the id from the model’s tool_use request. This pairing is how the model knows which result belongs to which request. Get it wrong and the model loses the connection between what it asked for and what came back.

{
  "role": "user",
  "content": [{
    "type": "tool_result",
    "tool_use_id": "toolu_01A09q90qw90lq917835lq9",
    "content": "Current weather in San Francisco: 62°F, partly cloudy"
  }]
}

It’s a user message

Tool results go in a message with role: "user". This is consistent with the API’s two-role model: the assistant side generates requests, the user side provides everything else. Your application executed the tool. Your application is on the user side. So the result is a user message.

There is no special “tool” role, no dedicated endpoint for tool results. It’s the regular /v1/messages endpoint, regular conversation flow.

Communicating errors

When a tool execution fails, you still send a tool_result — but with the error details in the content. The model can read the error, understand what went wrong, and decide what to do next (retry with different parameters, try a different tool, or tell the user).

Don’t silently drop failed tool calls. Don’t throw an exception that bypasses the API. Send the error back as a tool_result so the model can make an informed decision.

Why the roles make sense

The role assignment follows a simple rule: the role reflects who generated the content. The model generated the tool_use request, so it’s in an assistant message. Your application generated the tool_result, so it’s in a user message. The roles aren’t about the content type — they’re about the source.


One-liner: Tool results are user messages linked to the original request by tool_use_id — always send results back, even for errors, so the model can decide what to do next.