[Meta] tool_use/tool_result block mismatch causing bad conversation state (150+ reports)
Environment
- Platform (select one):
- [x] Anthropic API, others
- Claude CLI version: multiple, including 1.0.94; have encountered the issue after the alleged fix in 1.0.84
- Operating System: multiple
- Terminal: multiple
Bug Description
Claude Code users are experiencing conversation disruptions due to mismatched Tool Use and Tool Result blocks. This can occur due to transient network failures, server errors, or other failures around hook executions or tool calls. (Both times I have seen this in the past two weeks have been after a hook execution.) As of this writing the following issue tracker query ( is:issue Each tool_use block must have a corresponding tool_result block in the next message) shows 150+ issues.
Open Issues (63):
#5662, #6443, #6551, #3886, #3636, #6302, #5599, #5509, #3512, #3632, #3860, #4454, #3916, #3003, #5928, #5374, #6628, #5765, #3637, #2126, #6242, #2616, #2312, #5747, #1800, #3504, #2967, #2961, #2406, #2903, #2352, #2249, #2959, #3754, #6178, #2232, #2704, #4401, #2242, #2802, #5713, #1978, #4425, #3549, #2369, #6585, #2043, #2672, #2261, #4409, #3532, #4466, #3608, #1796, #2971, #3564, #4038, #3983, #5385, #6595, #769, #1672, #3982, #1608
Closed Issues (92):
#6575, #6566, #6539, #6567, #5705, #5989, #6521, #5468, #6363, #6410, #5424, #5375, #5450, #5317, #4842, #5060, #4638, #4664, #4563, #3086, #5470, #6343, #4096, #3639, #5594, #4825, #4180, #4798, #1887, #5193, #5479, #3101, #6348, #3331, #6502, #4877, #2697, #1831, #3149, #2157, #1782, #4522, #1776, #1686, #2840, #5410, #2796, #2828, #1894, #4134, #2600, #1574, #1237, #5457, #1881, #3902, #3977, #2179, #1968, #4159, #2201, #2423, #6490, #1747, #1642, #1969, #1738, #1584, #2630, #1577, #3862, #3202, #473, #1586, #1695, #5412, #1571, #5246, #3191, #1956, #1856, #4240, #2708, #1678, #1174, #1579, #558, #1761, #2494, #5476, #5421, #4211, #4283, #2045, #2582, #746, #3985, #4065, #3616, #1679
(My apologies to anyone whose issue was erroneously linked - I asked Claude to pull the gh issue list results together for me and did not verify each and every link.)
Most of the closed issues are closed because they are duplicates, not because they are resolved. Some of the closed issues have significant threads with multiple people confirming the issue, which means that the hit rate is significantly higher than 150+ issues.
One person developed a remediation, which involves exporting the conversation, clearing the history, restarting Claude Code, and then importing the conversation history. While it is good to have a workaround like this, it is obviously painful and an in-program mitigation would be preferred.
Steps to Reproduce
Not consistently reproducible.
Expected Behavior
Graceful recovery.
Actual Behavior
No more conversation turns can be generated.
Additional Context
To deal with this issue in my personal AI workbench last year, I developed the following Python code which can be adapted to Typescript/Node.js fairly easily. It makes an O(n) backwards pass through the message history, collecting tool use IDs from results and then detecting any tool uses which do not have those IDs in the collected set:
''' Filters out tool use blocks that have no matching result. '''
tool_result_ids = set( )
filtered_messages: list[ AnthropicMessage ] = [ ]
for message in reversed( messages ):
content = message[ 'content' ]
if not isinstance( content, list ):
filtered_messages.append( message )
continue
filtered_blocks = [ ]
for block in content:
if not isinstance( block, dict ):
filtered_blocks.append( block )
continue
match block.get( 'type' ):
case 'tool_result':
if 'tool_use_id' in block:
tool_result_ids.add( block[ 'tool_use_id' ] )
filtered_blocks.append( block )
case 'tool_use':
if block.get( 'id' ) in tool_result_ids:
filtered_blocks.append( block )
case _:
filtered_blocks.append( block )
if filtered_blocks:
message_filtered = dict( message )
message_filtered[ 'content' ] = filtered_blocks
filtered_messages.append( message_filtered )
return list( reversed( filtered_messages ) )
Or, you could open your sources so that others could help you patch serious issues....
46 Comments
It is indeed a rather irritating bug, especially since fixing it (or at least, adding a workaround while you figure out the root cause...) is really not very difficult. Claude code is essentially unusable at the moment for me.
@bcherny I remember you were on top of this issue last time I had it (source) thought it might be helpful to ping incase of useful context on prior fix etc!
My steps to reproduce:
invalid_request_error.screenshot of mine:
<img width="1464" height="307" alt="Image" src="https://github.com/user-attachments/assets/1054263b-0d74-410f-8d23-194a0a3b3f16" />
Thanks for pinging the lead developer, @zazer0 . Was tempted to do this soon, but wanted to give the team to work through the huge volume of issues they have before flagging harder. Looks like a couple of Anthropic-associated people are assigned now.
---
Update:
I've been bitten by this several more times in the past week, using the latest 1.0.1xy versions of Claude Code.
And here are the related issues which have come in since this issue was filed: #6859, #7327, #7484, #7570, #7691, #7796
This issue has a number of causes. While we are always monitoring instances of this error and and looking to fix them, it's unlikely we will ever completely eliminate it due to how tricky concurrency problems are in general. Feel free to share transcripts and complaints here, we'll keep an eye on this issue and close the many duplicates
Correct and this was stated in the original post (failed tool calls, transient network failures, server errors).
Part of what the original post suggested is that you mitigate the symptoms rather than trying to track down and eliminate every root cause. Some code, which is successfully used to mitigate them in another piece of software, was provided as reference.
I am betting that most people would rather have Claude Code drop an occasional failed hook (or whatever) and continue working than have their entire conversation come to a hard stop until they edit the offending tool uses/results out of the underlying JSON.
---
Open source agentic coders, like Opencode, have essentially caught up to you (and even surpassed you in some areas)... and can even use your models. And other ones, like Codex CLI and Gemini CLI, are rapidly closing the gap.
Your team seems fairly small. If it wants to spend its resources on creating rainbow-colored "ultrathink" keywords rather than mitigating actual user pain, that's fine, but it might not play out well over the course of the next few months.
This is killing me. It stops my autonomous workflows and prevents me from going back and forth in "finished" workflows.
For example, I can't interrupt a subagent and give it guidance because most of the time, in such cases, I get this error.
And sometimes subagents stop working, and I tell them to continue, only to find out they stopped because of this error, which reappears after my prompt.
I've given some examples and analyzed many related issues in https://github.com/anthropics/claude-code/issues/5374.
I've had this error from version v1.0.71, and I still have it in v1.0.126.
@wolffiex @igorkofman : Does Claude Code 2.0 use the recently-announced
context-management-2025-06-27beta header or are there plans to have it use this header? Based on my reading of the documentation, it seems to relax the API requirement for matching tool use and tool use result blocks. This would mitigate the majority, if not all of the issues, reported here, if true.Hint at possibly relaxed API strictness from documentation:
---
Edit: I see the 2.0 release notes do not say anything about the header but have this beacon of hope:
Thanks. Let's hope this is a real fix this time.
Happens maybe less often, but still there in 2.0.1 with Sonnet 4.5.
<img width="823" height="248" alt="Image" src="https://github.com/user-attachments/assets/9d7a3341-181b-40be-a563-45674fe94f3e" />
TypeScript Implementation Proposal
Here's a TypeScript/Node.js adaptation of the Python solution provided in the issue, with additional implementation ideas:
Root Cause
When a tool execution is interrupted (via Ctrl+C or timeout), Claude Code fails to insert the required
tool_resultblock, violating the Claude API specification that everytool_usemust be immediately followed by a correspondingtool_result.TypeScript Implementation
Interrupt Handler Implementation
Additionally, here's how to properly handle interrupts to prevent the issue:
Immediate Mitigation
For immediate relief, users can add this to their shell config to detect and warn about the issue:
Testing
I've tested the filter function with various scenarios including:
The TypeScript implementation is adapted from the Python solution in the original issue and has been verified to work correctly. The interrupt handler is a proposed approach to proactively prevent the issue.
Hope this helps!
Although I have seen no further problems myself, it is clear that many people are still being bitten by this. Here is the latest batch since last update (courtesy of Claude):
Open issues: #7929, #7947, #7991, #8004, #8077, #8187, #8201, #8303, #8325, #8425, #8507, #8612, #8652, #8746, #8763, #8783, #8790, #8817, #8818, #8821, #8847, #8867, #8887, #8893, #8894, #8895, #8903, #8929, #8931, #8940
Closed (as duplicate) issues: #7882, #8190, #8210, #8231, #8233, #8261, #8286, #8337, #8393, #8420, #8553, #8565, #8573, #8822
That is another 44 issues in the matter of several weeks, including after the alleged fix in 2.0.0, @wolffiex @igorkofman .
Summary of me rn: ahhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh
This is making Claude Code output the HOOKS OUTPUT as USER MESSAGES and KEEPS REACTING to them in a NEVERENDING LOOP basically.
Just unacceptable.
Why is this happening? I can supply you guys with all my hooks or my whole config if you like.
NEVER had this issue before Claude Code 2.0.
How/when would I use claude-check exactly? Could one surgically modify the transcript file to fix the issue, perhaps? @emcd
@semikolon : I am not the one who posted the one-liner. It was @jamestexas . That said, my reading is that it simply detects certain manifestations of the issue and recommends a restart. In my past experience, restarting does not fix the issue; one needs to actually edit the transcript. (But, it is possible that Claude 2.0.x has some sort of rectification on restart now. I have not experienced the issue since Claude 2.0.0, so I cannot confirm whether this is true. And, given the new usage limits, my probability of encountering the problem is about 1/6th of what it used to be....)
If you're asking whether I have suggestions about automatically editing the transcript, I could probably put something together. But, I would be concerned about Anthropic changing the format.... Anthropic really needs to address this from their end.
Thanks. That's weird, I've basically only experienced this issue since CC 2.0 / Sonnet 4.5 came out.
But I think it's due to concurrent tool use. I was about to let CC analyze my JSONL transcript files to identify patterns in what causes these errors. Started a subagent on reviewing transcripts and then hit my weekly limit seconds after 😝
😝 Ridiculous, isn't it? I really cannot get any useful work done with CC anymore. I've already started shifting to Codex CLI and have been evaluating Opencode with the latest DeepSeek model (and might give Grok Code Fast 1 another try too, even though my initial impressions were not good last month). At this point, metered API usage with the cheap models might be better than the scraps that are being handed out on the subscriptions. (Had a comfortable working relationship with Claude though. The other models are generally not as good at instruction following and lack the character that Claude has.) Might also go back to using the Mimeogram tool that I made earlier this year before the agentic coders let people tie to their subscriptions; the usage limits via the Claude.ai GUI do not seem as strict, especially if caching of project files is involved.
Anyway, I'm going to leave this bug report open since it is clear that you and others are still seeing problems with mismatched tool use blocks. The major trigger for the problem prior to Claude 2.0.0 was hooks running after parallel tool uses. Not sure what is happening now.
Should work ok with latest release. Haven't tried but otherwise here's a workaround which has worked for me:
Safety protocol for parallel tool call bug:
Add this to your CLAUDE.md to get rid of this issue until it's fixed by Anthropic (comment)
This issue has been inactive for 30 days. If the issue is still occurring, please comment to let us know. Otherwise, this issue will be automatically closed in 30 days for housekeeping purposes.
@semikolon (or anyone else): Do we need to keep this issue open? I personally have not been experiencing the problem for quite some time, but some of that may be due to drastically reduced Claude usage since the end of September. I think you have been more on top of it than I have.
I haven't had this issue for a long time either.
I just experienced it
Did you send in a full bug report?
Same as @marcosalins
Faced it today.
Same here:
I assume that everyone who is still seeing the problem has been running the latest version of Claude Code? I know that some people could still be running old versions if they disabled auto-update. (Not doubting the reports, but want to make sure that they are bullet-proof. It is extremely hard to get Anthropic's attention about problems that matter. Need to remove the excuses that they can use to ignore legitimate, serious reports.)
Also, you may want to file separate issues in addition to chiming in here. I started this issue to help Anthropic see the vastness of the problem (and because I was quite irritated about how long they had ignored the huge signal that their customers were giving them). However, there is no guarantee that they won't close this aggregator issue anyway, based on my past experience with them.
Claude Code v2.1.4 caught this thing again
Got this in 2.9.1
I still keep receiving:
⏺ PDF too large. Please double press esc to edit your message and try again.
and the loop. Tracing the duplicates, it ends up to this issue.
The below script might help to reproduce the issue. Test 2, 3 fail with: "API Error: 400 {"type":"error","error":{"type":"invalid_request_error","message":"messages.1.content.1:
tool_useids must be unique"},"request_id":"req_011CXV1YaSFDMfYRx7nHv37y"}"Verified failing with: Claude Code 2.1.19, on both: MacOS M3 and x86 Linux.
------------------------------------------------------------------------------------------------------------
#!/bin/bash
Manual test for Claude Code non-interactive mode with tool use
Run this in an external terminal to test Claude Code behavior
set -e
echo "=== Claude Code Non-Interactive Tool Test ==="
echo ""
echo "Claude Code version: $(claude --version)"
echo ""
Create test directory
TEST_DIR=$(mktemp -d)
echo "Test directory: $TEST_DIR"
Create test file
echo "Hello World from test file" > "$TEST_DIR/test.txt"
echo "Created: $TEST_DIR/test.txt"
echo ""
cd "$TEST_DIR"
echo "=== Test 1: No tool use (should work) ==="
echo "Command: claude -p \"what is 2+2?\" --settings '{}' --no-session-persistence --dangerously-skip-permissions"
echo ""
claude -p "what is 2+2?" --settings '{}' --no-session-persistence --dangerously-skip-permissions < /dev/null
echo ""
echo "Exit code: $?"
echo ""
echo "=== Test 2: Single tool use (may fail with v2.1.x bug) ==="
echo "Command: claude -p \"read test.txt\" --settings '{}' --no-session-persistence --dangerously-skip-permissions"
echo ""
claude -p "read test.txt" --settings '{}' --no-session-persistence --dangerously-skip-permissions < /dev/null || true
echo ""
echo "Exit code: $?"
echo ""
echo "=== Test 3: With --tools Read (may fail) ==="
echo "Command: claude -p \"read test.txt\" --settings '{}' --no-session-persistence --dangerously-skip-permissions --tools Read"
echo ""
claude -p "read test.txt" --settings '{}' --no-session-persistence --dangerously-skip-permissions --tools Read < /dev/null || true
echo ""
echo "Exit code: $?"
echo ""
echo "=== Test 4: With stream-json output (may fail) ==="
echo "Command: claude -p \"read test.txt\" --settings '{}' --no-session-persistence --dangerously-skip-permissions --output-format stream-json --verbose"
echo ""
claude -p "read test.txt" --settings '{}' --no-session-persistence --dangerously-skip-permissions --output-format stream-json --verbose < /dev/null 2>&1 | head -5 || true
echo ""
echo "Exit code: $?"
echo ""
Cleanup
rm -rf "$TEST_DIR"
echo "=== Cleanup done ==="
echo ""
echo "If tests 2-4 failed with 'tool_use ids must be unique' or 'tool use concurrency issues',"
echo "this confirms the Claude Code v2.1.x bug in non-interactive mode."
Thank you for the script, I can confirm that I have the same failing on Windows WSL - x64 :/
Session Recovery Script for sessions-index.json Out of Sync
If you're experiencing "session not found" errors, the issue may be that your
sessions-index.jsonis out of sync with the actual session.jsonlfiles on disk. This can happen when session files exist but aren't listed in the index.Quick Check
If the counts don't match, your index is out of sync.
Recovery Script
This Python script rebuilds the sessions index from all
.jsonlfiles found on disk:Usage
What This Fixes
This script addresses the symptom (out-of-sync index), not the root cause (orphaned
tool_resultblocks). If your session still won't resume after rebuilding the index, the session file itself is likely corrupted per the main issue description.Related Issues
Hope this helps others recover their "lost" sessions!
Sample provided:
I am on version 2.1.38, using Sonnet4.5 and am getting the same error:
Occurring on Opus 4.6 as well.
The workaround I found is to fire up a new Claude session and ask it to load context from previous one and continue.
My prompts below
I can confirm this issue exists for a Claude Chrome extension. Happens when you interrupt (click stop) frozen screenshot tool call. Makes crome extention unusable.
Specific repro: parallel tool calls + long session + /compact = orphaned
tool_resultatmessages[0]Hit this today in a session with 7192 JSONL lines. Sharing because it's a different failure mode than what's described above - the existing Python fix doesn't cover it.
What happened
Claude made 3 parallel tool calls in one assistant message (Read + Glob + Glob). In the JSONL, each result landed as a separate user record, all with the same
parentUuidpointing to the assistant:Only one of the three tool_results ends up on the main parent chain. The other two are dead-end branches.
Why /compact breaks
The session was very long (~7000 lines). When
/compactbuilds its API message array, context management appears to trim the start of the window. In my case the window started at5f52ce89- the tool_result - without including the preceding assistant message6ac87c53that had the three tool_uses.Result:
messages[0].content[0]is atool_resultwith no correspondingtool_usein any previous message:This is the REVERSE of the usual case
The existing Python fix (backward pass, filter orphaned tool_uses) handles: tool_use without a result.
This case is: tool_result without a preceding tool_use - which happens because the context window cuts between the tool_use message and the tool_result message.
Fix that worked (JSONL repair)
For anyone hitting this, here's a script that repairs the JSONL directly. It strips the tool_use blocks from the offending assistant message and converts the orphaned tool_result messages to plain text messages:
After running this,
/compactworked immediately.The underlying issue
The JSONL structure for parallel tool calls creates a branched tree - only one branch is the "main" thread. But that orphaned tool_result in the main thread is valid as long as the corresponding assistant tool_use is also in the context window. The bug is that the compaction window can be trimmed to start AFTER the tool_use message but BEFORE the tool_result, creating an invalid API request.
The fix at the compaction layer would be: when trimming the start of the context window, if the first message is a
tool_result, walk back further until you find a message that isn't a tool_result (or discard those tool_results along with their paired tool_uses).@wolffiex It seems the problem is only getting worse... The agent is now stopping and acting up very frequently. The only thing that helps is ESC and restarting with the "continue" request. If the Anthropic vibe coding approach can't fix the problem, I think they should open-source the agent, and we'll fix it!
We kept hitting this in our own sessions — especially after pruning or compaction. Built cozempic to fix it and open-sourced it.
As of v0.7.6, it handles orphaned
tool_resultblocks in two ways:tool_resultblocks whose matchingtool_usewas removed and strips them out before savingcozempic doctordetects orphans in existing sessions and--fixrepairs themWould appreciate feedback from anyone dealing with this.
Didn't fix the orphaned tool_result in my case. Says its ok but still getting the error. Restarting did the trick.
same issue
We reverse-engineered
cli.jsacross 12 npm versions and analyzed 1,571 sessions (148,444 tool calls, 8,007 orphaned) to find the root causes of this and related hang/orphan issues.Full analysis with code offsets and fix proposals: #33949
Nice work... work that you should not have had to perform if Anthropic were as accountable and transparent as they claim. (If they were accountable, they would actually respond to serious issues. And, if they were transparent, they would open source Claude Code. It is not their "secret sauce"; their models are good, Claude Code is not.) Sadly, they have serious issues which have been open for many months, some of which have hundreds of comments (and more than a thousand, in one case), and they simply sit on those issues without responding. Reverse engineering is the easy part; getting Anthropic to actually listen to what their paying customers are telling them is the hard part. I wish you success but will not be holding my breath.
Fully agree. We've been saying the same thing since September 2025:
Both were auto-closed and locked by the bot without any response from the team. In fact, across all related issues (#26224, #25979, #20171, #24688) — zero replies from Anthropic. The only team response in 6+ months was @wolffiex on this issue back in September 2025: "it's tricky". That's it.
What's frustrating is that Claude Code is genuinely a great tool at its core. But every release ships a pile of new features while the basic workflow — submit prompt, get response, press ESC to cancel — remains broken. Priorities seem inverted: new shiny features over core reliability.
As Karpathy put it, the real value comes when you know exactly what you want and engineer it properly — not when you vibe-code your way through production. We wrote about this exact problem: From Vibe Coding to Agentic Engineering.
We made ready-to-use prompts for @bcherny — just copy-paste into Claude Code and it will fix itself: 6 prompts to fix Claude Code with Claude Code
Workflow setup, 3 bug fixes, full codebase audit, and 35+ enterprise regression tests — all copy-paste ready. Since 100% of Claude Code is written by Claude Code, should take about 6 hours.
Also experiencing this issue in VSCode extension (reported in #45036). Subscribing for updates on the resolution progress.