-
-
Notifications
You must be signed in to change notification settings - Fork 52.7k
Description
Summary
When a user sends a message while an assistant tool call is in-flight, OpenClaw saves an orphaned tool_use block to the transcript with no corresponding tool_result. On the next LLM request, Anthropic's API rejects the malformed message history with:
LLM request rejected: messages.115: `tool_use` ids were found without `tool_result` blocks immediately after: callfunctionbhjp2y1evppn1. Each `tool_use` block must have a corresponding `tool_result` block in the next message.
This causes full session downtime until the gateway is manually restarted.
Reproduction
- Send a message that triggers a tool call (e.g. any exec or browser call)
- While the tool is executing, send another message
- OpenClaw interrupts the tool call and processes the new message
- The transcript now has an orphaned
tool_usewith notool_result - All subsequent LLM calls for that session fail
Expected Behavior
OpenClaw should inject a synthetic tool_result block when a user message interrupts an in-flight tool call, e.g.:
{
"type": "tool_result",
"tool_use_id": "<orphaned_id>",
"content": "Tool call interrupted by user message.",
"is_error": true
}This is what Anthropic expects and would allow the session to recover gracefully without a gateway restart.
Actual Behavior
The orphaned tool_use is persisted to the transcript. Every subsequent LLM request fails until the transcript is repaired or the session is reset.
Environment
- OpenClaw version: latest (npm)
- Provider: Anthropic (claude-sonnet-4-6)
- Platform: macOS Darwin 25.2.0 arm64
Workaround
Gateway restart clears the in-memory session state. We've also built a local watchdog (orphaned-tool-heal.sh) that detects the error pattern in logs and auto-restarts, but this is a band-aid — the correct fix is for OpenClaw to prevent the corruption in the first place.
References
- OpenClaw
sessions-GqMGg4XE.jshasTOOL_CALL_TYPESandTOOL_RESULT_TYPESsets andcountToolResults()— the detection primitives exist, just no repair logic. - The
abortedLastRunflag exists in session state but doesn't appear to trigger any transcript repair.