Skip to content

Orphaned tool_use block when user message interrupts in-flight tool call — session permanently broken #32098

@seneca-torres

Description

@seneca-torres

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

  1. Send a message that triggers a tool call (e.g. any exec or browser call)
  2. While the tool is executing, send another message
  3. OpenClaw interrupts the tool call and processes the new message
  4. The transcript now has an orphaned tool_use with no tool_result
  5. 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.js has TOOL_CALL_TYPES and TOOL_RESULT_TYPES sets and countToolResults() — the detection primitives exist, just no repair logic.
  • The abortedLastRun flag exists in session state but doesn't appear to trigger any transcript repair.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions