close
Skip to content

[Meta] tool_use/tool_result block mismatch causing bad conversation state (150+ reports) #6836

@emcd

Description

@emcd

Environment

  • Platform (select one):
    • 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....

Metadata

Metadata

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions