Unrecoverable session after dropped tool_result — rewind/restore/summarize all fail

Status Closed — not planned
Maintainer reply None cached
Activity 12 comments · opened Mar 26, 2026 · closed Jun 1, 2026

When a tool_result is dropped mid-conversation, the session enters a permanently unrecoverable state. All built-in recovery mechanisms fail with the same 400 error.

What happened

  1. A Bash tool call (git log --oneline | wc -l) executed but returned (No output) — the tool_result appears to have been dropped or malformed
  2. Every subsequent message fails: API Error: 400 due to tool use concurrency issues
  3. /rewind offers three options: Restore conversation, Summarize from here, Never mind
  4. All three fail with the same 400 error
  5. The session is permanently unusable — no recovery path works

Root cause

The Anthropic API requires every tool_use block to have a matching tool_result. When a result is dropped, the conversation history becomes structurally invalid. The recovery mechanisms (rewind, restore, summarize) reconstruct the API conversation from the same broken history, reproducing the invalid tool_use/tool_result sequence.

Even amputating 200+ entries from the session JSONL does not fix it, suggesting the broken pair may be embedded in compacted/summarized history that amputation cannot reach.

Expected behavior

At minimum one of these should work:

  • /rewind "Restore conversation" should inject a synthetic tool_result for any orphaned tool_use blocks
  • /rewind "Summarize from here" should discard the raw history and start fresh from a summary, skipping broken tool pairs
  • Claude Code should detect orphaned tool_use blocks before sending to the API and auto-repair them

Impact

  • Session is permanently dead — $50+ of context and work history lost
  • All commits were on disk (no code lost), but session continuity is destroyed
  • Related issues: #20555, #37452, #21321 — but those don't address the recovery failure

Environment

  • Claude Code v2.1.84
  • macOS
  • Model: Opus 4.6

View original on GitHub ↗

11 Comments

github-actions[bot] · 5 months ago

Found 3 possible duplicate issues:

  1. https://github.com/anthropics/claude-code/issues/31328
  2. https://github.com/anthropics/claude-code/issues/8484
  3. https://github.com/anthropics/claude-code/issues/37452

This issue will be automatically closed as a duplicate in 3 days.

  • If your issue is a duplicate, please close it and 👍 the existing issue instead
  • To prevent auto-closure, add a comment or 👎 this comment

🤖 Generated with Claude Code

ppiankov · 5 months ago

We built a workaround for this in contextspectre v0.46.0:

contextspectre rewire <session-id> --apply

It scans the session JSONL for tool_use blocks without matching tool_result entries and injects synthetic results to make the conversation structurally valid again. Also runs automatically as part of contextspectre launch pre-flight.

The root fix still belongs in Claude Code — /rewind should be able to repair orphaned tool_use blocks instead of replaying the same broken history.

ppiankov · 5 months ago

This is not a duplicate of the linked issues. #31328, #8484, and #37452 report the 400 error itself. This issue reports that all recovery mechanisms also fail — /rewind "Restore conversation", "Summarize from here", and "Never mind" all reproduce the same 400 because they reconstruct from the same broken history.

The root cause is specific: a dropped tool_result creates a structurally invalid conversation that no existing recovery path can repair. The fix is to inject a synthetic tool_result for orphaned tool_use blocks before replaying the history.

lotz · 5 months ago

This is a clear regression in version 2.1.85. Downgrading to 2.1.84 (https://code.claude.com/docs/en/setup#advanced-installation-options) works with the same resumed conversation. It's reproducible in multiple conversations that were working fine in 2.1.84 and now fail with this error in 2.1.85 once resumed. I do not see any mismatched tool_use/tool_results in my context either, using some "repair" tools to check them.

dark942 · 5 months ago

Adding another reproduction path: /resume triggers the 400 error on the very first message.

  1. Had a working conversation with tool use
  2. Ended the session
  3. /resumed the conversation
  4. Sent one message ("so")
  5. Immediate API Error: 400 due to tool use concurrency issues

/rewind did nothing — the corruption is baked into the reconstructed history from /resume, not in a rewindable turn.

Platform: Linux (Arch), CLI terminal.

lotz · 5 months ago

@ashwin-ant

agambon · 5 months ago

One more reproduction path (Opus):

  1. I ask the model to perform an operation, trace a logic flow, etc.
  2. The model launches the Agent: function. I suppose this is a sub-agent tool call?
  3. The extension crashes with an endless Not responding error.

If the model instead does the operation itself instead of launching a sub-agent, it works fine.

yurukusa · 5 months ago

A PostToolUse hook can detect and log potential dropped results before they corrupt the session:

INPUT=$(cat)
TOOL=$(echo "$INPUT" | jq -r '.tool_name // empty')
OUTPUT=$(echo "$INPUT" | jq -r '.tool_output // empty')
if [ -z "$OUTPUT" ] || [ "$OUTPUT" = "null" ] || [ "$OUTPUT" = "(No output)" ]; then
    case "$TOOL" in
        Bash)
            CMD=$(echo "$INPUT" | jq -r '.tool_input.command // empty')
            if echo "$CMD" | grep -qE '(git log|ls|cat|find|grep|wc|echo|pwd)'; then
                echo "⚠️ Empty result from $TOOL: $CMD — possible dropped result" >&2
                echo "Consider /compact if the session becomes unstable" >&2
                echo "$(date -u +%Y-%m-%dT%H:%M:%SZ) EMPTY_RESULT tool=$TOOL cmd=$CMD" >> /tmp/cc-result-log.txt
            fi
            ;;
        Read|Grep|Glob)
            echo "⚠️ Empty result from $TOOL — file may not exist or result was dropped" >&2
            ;;
    esac
fi
exit 0

For proactive session checkpointing (to recover from corruption):

COUNTER="/tmp/cc-checkpoint-counter"
COUNT=$(cat "$COUNTER" 2>/dev/null || echo 0)
COUNT=$((COUNT + 1))
echo "$COUNT" > "$COUNTER"
if [ $((COUNT % 20)) -eq 0 ]; then
    CHECKPOINT="/tmp/cc-checkpoint-$(date +%s).txt"
    echo "Tool calls: $COUNT" > "$CHECKPOINT"
    echo "Branch: $(git branch --show-current 2>/dev/null)" >> "$CHECKPOINT"
    echo "Changed files: $(git diff --name-only 2>/dev/null)" >> "$CHECKPOINT"
    echo "Recent commits: $(git log --oneline -3 2>/dev/null)" >> "$CHECKPOINT"
fi
exit 0

If the session does become unrecoverable, resume from a checkpoint with claude --resume or start a new session with claude -p "Continue from checkpoint: $(cat /tmp/cc-checkpoint-*.txt | tail -20)"

junaidtitan · 4 months ago

Cozempic v1.6.11's doctor command diagnoses and repairs this: cozempic doctor --fix detects orphaned tool_result blocks and repairs them. The executor also has fix_orphaned_tool_results() that runs automatically after every treatment. Sibling tool_use protection prevents the orphaning in the first place.

pip install cozempic && cozempic init

junaidtitan · 3 months ago

Dropped tool_results making the session unrecoverable is exactly the kind of corruption cozempic's doctor can detect and fix. The orphaned-tool-results check finds these dangling entries and the executor repairs them so the session becomes usable again. pip install cozempic && cozempic doctor https://github.com/Ruya-AI/cozempic — happy to hear how it goes.

github-actions[bot] · 3 months ago

Closing for now — inactive for too long. Please open a new issue if this is still relevant.

Showing cached comments. Read the full discussion on GitHub ↗