Session corruption: orphaned tool_use/tool_result entries cause unrecoverable 400 concurrency error
Session corruption: orphaned tool_use/tool_result entries cause unrecoverable "API Error: 400 due to tool use concurrency issues"
Description
A long-running session (~3100 JSONL lines, ~27MB) became permanently unrecoverable after pasting 8 base64 images in a single message. Every subsequent prompt — including after multiple /rewind attempts and claude --resume — returns:
API Error: 400 due to tool use concurrency issues. Run /rewind to recover the conversation.
Root cause
Analysis of the JSONL conversation file revealed orphaned tool_use/tool_result pairs scattered throughout the history:
| Line | Issue | Details |
|------|-------|---------|
| L2 | tool_result with no matching tool_use | References a toolu_* ID that doesn't exist in the file |
| L762 | tool_use with no matching tool_result | Bash call — no result ever recorded |
| L2275 | tool_use with no matching tool_result | Bash call — no result ever recorded |
Stats: 714 tool_use entries, 713 tool_result entries, 2 orphan uses, 1 orphan result.
These orphaned entries produce an invalid API request when the conversation is replayed (tool_use without a following tool_result violates the API's message structure requirements).
Why /rewind doesn't help
/rewind removes the last user/assistant exchange pair from the tail of the conversation. But the orphaned entries are at L2, L762, and L2275 — deep in the history. No amount of rewinding can reach them without destroying the entire session.
Trigger
The error first appeared when pasting a user message containing 8 base64-encoded PNG screenshots (~3.5MB total). The submission produced two consecutive user lines in the JSONL:
- L3031: user message with text + 8 base64 image content blocks
- L3032: a second user message with 8 text blocks containing
[Image: source: /path/to/file.png]path references
This double-user-message is itself invalid, but even after manually removing it, the session remained broken due to the pre-existing orphaned tool entries listed above.
Reproduction
Not easily reproducible on demand, but the conditions were:
- Long session with heavy tool use (~714 tool calls, multiple context compactions)
- Session continued from a previous conversation that ran out of context (visible at L2735)
- Multiple parallel tool calls throughout (normal Claude Code behavior)
- Large multi-image paste as the triggering event
Suggested fixes
- JSONL serializer: Ensure every
tool_usegets a correspondingtool_resultwritten, even if the tool call was cancelled, timed out, or errored. Write a synthetic error result if needed. - Session replay: Validate tool_use/tool_result pairing when loading a session. Inject synthetic results for orphaned uses, and drop orphaned results, before sending to the API.
- Image handling: Don't split a single user submission into two separate
userJSONL entries (the base64 images and the path metadata should be one entry). - Better /rewind: When the 400 error occurs, offer a deep repair option that scans and fixes structural issues, rather than only trimming the tail.
Environment
- Claude Code CLI (latest as of 2026-03-26)
- macOS Darwin 25.4.0
- Session file: ~27MB, ~3100 lines, 714 tool calls
This issue has 5 comments on GitHub. Read the full discussion on GitHub ↗