Bug Report: ServerToolResult not delivered when client tools interrupt the stream
Summary
When the Messages API returns stop_reason=tool_use (requesting execution of a client-defined tool) while server-side tools (code_execution, web_search) are running concurrently in the same turn, the ServerToolResult content blocks for those server tools are never delivered to the caller — neither during streaming, in the final message, nor in the subsequent API call.
Reproduction
Setup
- Model:
claude-sonnet-4-6 (also observed on claude-opus-4-6)
- Tools:
code_execution_20250825 (server-side) + a client-defined tool (e.g. ask_internal_tool)
- Streaming mode via Python SDK
client.messages.stream()
Steps
- Send a message that triggers Claude to invoke both a server tool and a client tool in the same turn
- Example prompt: "Search our database for port activity data and create an Excel spreadsheet with a benchmarking report" (where the database search is a client-side tool)
What happens
- Stream begins
content_block_start with server_tool_use (e.g. text_editor_code_execution, id=srvtoolu_A)
content_block_start with server_tool_use (e.g. web_search, id=srvtoolu_B)
content_block_start with tool_use (client tool, id=toolu_C)
message_delta with stop_reason=tool_use
message_stop
Missing: No content_block_start with text_editor_code_execution_tool_result for srvtoolu_A, no web_search_tool_result for srvtoolu_B. The stream ends before these arrive.
What happens in the next API call
- We send the client tool result back in the conversation
- Claude continues and produces the file successfully using new tool calls
- The original
srvtoolu_A and srvtoolu_B results are never delivered as content blocks — neither in the streaming events nor in get_final_message()
Expected behavior
Either:
- (a) The stream should wait for all pending server tools to complete before returning
stop_reason=tool_use, OR
- (b) The
ServerToolResult blocks should be included in the response of the next API call (since the results were computed and are available in the container), OR
- (c) The
get_final_message() from the first call should include the ServerToolResult blocks for tools that completed while the stream was open
Impact
Any application that uses server-side tools (code_execution, web_search) alongside client-defined tools will have orphaned server_tool_use blocks with no matching result. This causes:
- Frontend stuck spinners — tool progress UI shows a tool as "running" forever
- Incorrect error detection — monitoring/load tests flag these as failures even though the operation succeeded
- Workaround burden — applications must implement heuristic cleanup (assume completion at next iteration) rather than relying on the API contract
Evidence
From our production load test (5 concurrent users, file-generation questions):
| Test |
Orphaned tools |
File produced? |
stop_reason |
| user_2 q1 |
text_editor_code_execution |
Yes |
end_turn |
| user_3 q1 |
text_editor_code_execution |
Yes |
end_turn |
| user_4 q1 |
text_editor_code_execution + web_search |
Yes |
end_turn |
| user_5 q1 |
text_editor_code_execution + web_search |
Yes |
end_turn |
All cases: server tool started at t=4-6s, client tool started at t=7-14s, stream ended for client tool. Server tool result never delivered. File was eventually produced in subsequent iterations.
Raw event trace (user_4, showing both orphaned types)
t=4.1s content_block_start server_tool_use text_editor_code_execution (srvtoolu_A)
t=4.7s content_block_start server_tool_use web_search (srvtoolu_B)
t=7.9s content_block_start tool_use ask_internal_tool (toolu_C)
... no content_block_start for *_tool_result for srvtoolu_A or srvtoolu_B ...
message_delta stop_reason=tool_use
message_stop
--- Next API call (with toolu_C result) ---
t=319s content_block_start server_tool_use text_editor_code_execution (srvtoolu_D) <- NEW tool
... srvtoolu_A and srvtoolu_B results never appear ...
Environment
- anthropic Python SDK version: 0.52.0
- Model: claude-sonnet-4-6
- Tools:
code_execution_20250825 + custom client tools
- Streaming: yes
- Container: reused across iterations via
container.id
Workaround
We emit synthetic tool_result events for orphaned server tools at the start of the next agentic loop iteration, assuming they completed successfully (since Anthropic continues the conversation without error).
Bug Report: ServerToolResult not delivered when client tools interrupt the stream
Summary
When the Messages API returns
stop_reason=tool_use(requesting execution of a client-defined tool) while server-side tools (code_execution,web_search) are running concurrently in the same turn, theServerToolResultcontent blocks for those server tools are never delivered to the caller — neither during streaming, in the final message, nor in the subsequent API call.Reproduction
Setup
claude-sonnet-4-6(also observed onclaude-opus-4-6)code_execution_20250825(server-side) + a client-defined tool (e.g.ask_internal_tool)client.messages.stream()Steps
What happens
content_block_startwithserver_tool_use(e.g.text_editor_code_execution, id=srvtoolu_A)content_block_startwithserver_tool_use(e.g.web_search, id=srvtoolu_B)content_block_startwithtool_use(client tool, id=toolu_C)message_deltawithstop_reason=tool_usemessage_stopMissing: No
content_block_startwithtext_editor_code_execution_tool_resultforsrvtoolu_A, noweb_search_tool_resultforsrvtoolu_B. The stream ends before these arrive.What happens in the next API call
srvtoolu_Aandsrvtoolu_Bresults are never delivered as content blocks — neither in the streaming events nor inget_final_message()Expected behavior
Either:
stop_reason=tool_use, ORServerToolResultblocks should be included in the response of the next API call (since the results were computed and are available in the container), ORget_final_message()from the first call should include theServerToolResultblocks for tools that completed while the stream was openImpact
Any application that uses server-side tools (
code_execution,web_search) alongside client-defined tools will have orphanedserver_tool_useblocks with no matching result. This causes:Evidence
From our production load test (5 concurrent users, file-generation questions):
text_editor_code_executionend_turntext_editor_code_executionend_turntext_editor_code_execution+web_searchend_turntext_editor_code_execution+web_searchend_turnAll cases: server tool started at t=4-6s, client tool started at t=7-14s, stream ended for client tool. Server tool result never delivered. File was eventually produced in subsequent iterations.
Raw event trace (user_4, showing both orphaned types)
Environment
code_execution_20250825+ custom client toolscontainer.idWorkaround
We emit synthetic
tool_resultevents for orphaned server tools at the start of the next agentic loop iteration, assuming they completed successfully (since Anthropic continues the conversation without error).