Summary
Using a self-hosted EnvironmentWorker with multiagent enabled, confirming a tool_result for a tool that ran inside a non-primary session_thread_id (a sub-thread) intermittently fails with a 400:
Error code: 400 - invalid_request_error:
`tool_use_id` "sevt_..." does not match any `agent.tool_use` event in this session
The tool itself executes successfully; only the result confirmation is rejected. Because _send_result treats the 400 as fatal (no re-fetch, no retry after SEND_RETRIES), a transient failure becomes a permanent strand: the session sits in requires_action until an external user.interrupt.
Environment
anthropic==0.112.0
- Self-hosted
EnvironmentWorker(...).handle_item(...)
- Multiagent enabled via
beta_agent_toolset_20260401 (orchestrator spawns sub-threads)
- The worker only supplies tools; all tool-result posting is done inside the SDK.
What I observe (from session event traces)
- The failing
tool_use_ids are agent.tool_use events whose session_thread_id is a sub-thread (sthr_...), not the primary session.
- The failing tools are ordinary toolset tools (
bash, read) with evaluated_permission: "allow" — not always_ask.
- It is intermittent: the same tool, in the same sub-thread, with the same permission, sometimes succeeds. It frequently affects the second of two near-simultaneous
agent.tool_use blocks issued in one sub-thread turn (the first is confirmed, the second 400s).
- It self-heals ~11 minutes later on a re-drive: a
user.tool_result for the same tool_use_id eventually appears, carrying the correct session_thread_id. So the SDK does route to the sub-thread correctly when it succeeds.
- The final pending
agent.tool_use in a chain does not self-heal; the session stays in requires_action until interrupted.
- Custom-tool results (
agent.custom_tool_use / user.custom_tool_result) are unaffected in the same sessions.
Example trace shape (one session): 6 agent.tool_use but only 4 user.tool_result; all shortfall ids are sub-thread agent.tool_use.
Questions
- When confirming a
tool_use that ran on a non-primary session_thread_id, should the SDK scope the confirmation to that session_thread_id? (It does when it succeeds, so this may be a timing issue rather than a missing field.)
- Is this a server-side commit-ordering race — the
agent.tool_use event not yet matchable when the result is posted — surfaced as a 400?
- Given a
400 here is often transient, should _send_result re-fetch the session's pending events and retry rather than treating it as fatal? Today a transient race permanently strands the session.
Likely related (TypeScript SDK): anthropics/anthropic-sdk-typescript#1083.
Summary
Using a self-hosted
EnvironmentWorkerwith multiagent enabled, confirming atool_resultfor a tool that ran inside a non-primarysession_thread_id(a sub-thread) intermittently fails with a400:The tool itself executes successfully; only the result confirmation is rejected. Because
_send_resulttreats the400as fatal (no re-fetch, no retry afterSEND_RETRIES), a transient failure becomes a permanent strand: the session sits inrequires_actionuntil an externaluser.interrupt.Environment
anthropic==0.112.0EnvironmentWorker(...).handle_item(...)beta_agent_toolset_20260401(orchestrator spawns sub-threads)What I observe (from session event traces)
tool_use_ids areagent.tool_useevents whosesession_thread_idis a sub-thread (sthr_...), not the primary session.bash,read) withevaluated_permission: "allow"— notalways_ask.agent.tool_useblocks issued in one sub-thread turn (the first is confirmed, the second400s).user.tool_resultfor the sametool_use_ideventually appears, carrying the correctsession_thread_id. So the SDK does route to the sub-thread correctly when it succeeds.agent.tool_usein a chain does not self-heal; the session stays inrequires_actionuntil interrupted.agent.custom_tool_use/user.custom_tool_result) are unaffected in the same sessions.Example trace shape (one session): 6
agent.tool_usebut only 4user.tool_result; all shortfall ids are sub-threadagent.tool_use.Questions
tool_usethat ran on a non-primarysession_thread_id, should the SDK scope the confirmation to thatsession_thread_id? (It does when it succeeds, so this may be a timing issue rather than a missing field.)agent.tool_useevent not yet matchable when the result is posted — surfaced as a400?400here is often transient, should_send_resultre-fetch the session's pending events and retry rather than treating it as fatal? Today a transient race permanently strands the session.Likely related (TypeScript SDK): anthropics/anthropic-sdk-typescript#1083.