Skip to content

Session compaction breaks tool_use/tool_result pairing, causing 400 API errors #27804

Description

@JakeLiuMe

Bug Description

When a long-running session (e.g., Discord channel) accumulates many messages and goes through compaction, orphaned tool_result blocks can be sent to the Anthropic API without their matching tool_use. This causes a 400 invalid_request_error that permanently bricks the session — the bot can never respond again in that channel.

Root Cause

Observed in a Discord channel session (6,724 JSONL entries, 23 compactions):

  1. An assistant request is aborted mid-tool-call (stopReason: "aborted")
  2. The toolCall block and its toolResult message are both recorded in the JSONL
  3. When compaction runs, the conversation is summarized — but the toolResult entry survives into the post-compaction message window while its matching toolCall does not
  4. On the next API call, Anthropic receives a tool_result referencing a tool_use_id that doesn't exist in the conversation
  5. API returns: messages.166.content.1: unexpected tool_use_id found in tool_result blocks
  6. Every subsequent API call fails with the same error — the session is bricked

Reproduction

This happened naturally in a Discord channel session after ~2 weeks of continuous use. The JSONL had:

  • Line 6716: Assistant message with toolCall (stopReason: "aborted")
  • Line 6717: toolResult message referencing that tool call
  • Line 6719: Compaction entry (parentId chain includes both 6716 and 6717)
  • Line 6721: Next assistant message → 400 error

Expected Behavior

Compaction should ensure tool_use/tool_result pairs are always kept or removed together. If a toolCall is summarized away, its corresponding toolResult must also be excluded from the API request.

Suggested Fix

When building the API message array from the JSONL:

  1. After compaction, validate that every tool_result has a matching tool_use in the message array
  2. Strip orphaned tool_result blocks before sending to the API
  3. Consider also handling orphaned tool_use blocks (tool_use without a following tool_result)

Alternatively, during compaction:

  • Ensure aborted tool calls and their results are either both kept or both summarized
  • Never split a tool_use/tool_result pair across a compaction boundary

Workaround

Manually clearing the session transcript (.jsonl file) restores functionality but loses all conversation history.

Environment

  • OpenClaw: 2026.2.22-2
  • Provider: Anthropic (Claude Opus 4.6)
  • Session type: Discord channel (long-running, continuous)
  • OS: macOS 15.7.3

Metadata

Metadata

Assignees

No one assigned

    Labels

    staleMarked as stale due to inactivity

    Type

    No type

    Fields

    Priority

    None yet

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions