Skip to content

bug: compaction preserves orphaned tool_use blocks after request timeout, permanently breaking session #93321

Description

@dolphinsboy

Description

When an LLM request times out mid-turn while the agent has pending parallel tool calls (tool_use blocks without corresponding tool_result blocks), OpenClaw's compaction mechanism preserves the orphaned tool_use blocks in the compacted history. This causes every subsequent API call to be permanently rejected with a ValidationException: messages.N: tool_use ids were found without tool_result blocks error, rendering the agent completely unresponsive.

Steps to Reproduce

  1. Run an agent in a session with heavy tool usage (e.g., multiple parallel web_fetch + memory_search calls)
  2. Allow context to grow large enough (~60–70% of limit) to trigger a provider-side request timeout mid-turn
  3. The timeout interrupts the turn while 3 tool_use blocks are pending but no tool_result has been received yet
  4. OpenClaw attempts compaction to reduce context size
  5. The compaction preserves the orphaned tool_use blocks (without their tool_result pairs) in the compacted history
  6. Every subsequent message to the agent fails with:
    ValidationException: messages.57: `tool_use` ids were found without `tool_result` blocks immediately after:
    toolu_9088da77b54b43f18a3af238, toolu_b0bb3eae150346efb982621b, toolu_dc61dfdd7a2844f886a01315.
    Each `tool_use` block must have a corresponding `tool_result` block in the next message.
    
  7. The agent shows [assistant turn failed before producing content] on every subsequent message
  8. The compaction retry loop amplifies the problem: each compaction attempt re-embeds the same broken tool_use blocks, creating duplicate orphaned entries across the session history

Root Cause

In OpenClaw's compaction logic, when the session history is truncated/summarized, there is no validation that every tool_use block in the retained history has a corresponding tool_result block immediately following it.

The Anthropic API (and AWS Bedrock's Claude endpoint) strictly requires that every tool_use block be immediately followed by its tool_result in the next message. When compaction truncates at a boundary that splits a (tool_use → tool_result) pair, the orphaned tool_use block poisons the entire session permanently.

Observed in session a7c86c90-f74b-41a9-980b-70a4c6fb8570 (wukongim agent):

  • First timeout: 2026-06-15T09:04 (context: ~118k tokens, provider request timeout)
  • Broken tool_use IDs first appeared at event index [74]: toolu_dc61dfdd…, toolu_b0bb3eae…, toolu_9088da77…
  • Compaction re-ran at: 10:53, 11:04, 11:13 — each time re-embedding the same broken blocks
  • Agent became permanently unresponsive from 17:36 onward (~6 hours of failed retries)

Expected Behavior

Compaction should validate tool_use / tool_result pairing integrity before finalizing the compacted history. If a truncation boundary would leave a tool_use block without its tool_result, the compaction should either:

  1. Drop the entire unpaired turn (discard the orphaned tool_use block along with any partial context around it), or
  2. Inject a synthetic tool_result with an error/cancelled status so the message sequence remains valid

This would prevent a single LLM timeout from permanently corrupting a session.

Suggested Fix

In the compaction module, after generating the truncated/summarized message list, add a post-processing validation pass:

for each message in compacted_history:
    if message contains tool_use blocks:
        next_message = compacted_history[i + 1]
        if next_message does not contain tool_result for all tool_use IDs:
            remove the tool_use message (and its partial tool_result if any) from compacted_history

Alternatively, detect orphaned tool_use blocks at request-build time and strip them before sending to the provider, logging a warning.

Workaround

Delete or reset the agent's sessionId in sessions.json and restart the gateway. This forces a fresh session on the next message, discarding the corrupted history.

Environment

  • OpenClaw version: 2026.5.28 (e932160)
  • Provider: Anthropic Claude (via AWS Bedrock, anthropic-messages API)
  • Model: anthropic/ml4.6-plus (claude-sonnet-4-6)
  • Trigger condition: provider-side request timeout during a turn with multiple parallel tool calls
  • truncateAfterCompaction: true was configured in agents.defaults.compaction but did not prevent the corruption (the timeout happened before compaction could cleanly reset the context)

Metadata

Metadata

Assignees

No one assigned

    Labels

    P1High-priority user-facing bug, regression, or broken workflow.clawsweeper:linked-pr-openClawSweeper found an open linked pull request for this issue.clawsweeper:needs-live-reproClawSweeper needs live local, crabbox, or manual validation to confirm this issue.clawsweeper:no-new-fix-prClawSweeper does not recommend queueing a new automated fix PR for this issue.impact:session-stateSession, memory, transcript, context, or agent state can drift or corrupt.issue-rating: 🐚 platinum hermitGood issue quality with a plausible reproduction path needing some confirmation.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