spacehub

surshar / claude-code

Claude Code is an agentic coding tool that lives in your terminal, understands your codebase, and helps you code faster by executing routine tasks, explaining complex code, and handling git workflows - all through natural language commands.

Built by Anthropic · github.com/anthropics

claude-code / .github / issues / duplicate-tool-result-bug.md
123 lines · 3.9 KBPreviewCodeRaw
1# Bug Report: Duplicate tool_result blocks with same tool_use_id
2
3## Summary
4When a tool call fails (particularly observed with the Tmux tool), two `tool_result` blocks are incorrectly sent to the API with the same `tool_use_id`, causing an API error:
5
6```
7API Error: 400
8{"type":"error","error":{"type":"invalid_request_error","message":"messages.X.content.1: each tool_use must have a single result. Found multiple `tool_result` blocks with id: toolu_XXX"}}
9```
10
11## Root Cause
12The parallel tool execution error handling code sends a "Sibling tool call errored" message even for the tool that actually failed, when it should only send this message for OTHER sibling tools in the parallel batch.
13
14## Reproduction
151. Execute a tool call that will fail (e.g., Tmux select-pane on a non-existent window)
162. Observe two tool_result messages being generated:
17 - First: The actual error result ("Window not found...")
18 - Second: A "<tool_use_error>Sibling tool call errored</tool_use_error>" message with the SAME tool_use_id
19
20## Example JSON (from reported incident)
21```json
22// Assistant requests tool use
23{
24 "type": "tool_use",
25 "id": "toolu_01K2K2KFvUrwA9PaHGp652zW",
26 "name": "Tmux",
27 "input": {"args": ["select-pane", "-t", "test-perms3:0.0"]}
28}
29
30// First tool_result (correct - actual error)
31{
32 "type": "user",
33 "message": {
34 "role": "user",
35 "content": [{
36 "tool_use_id": "toolu_01K2K2KFvUrwA9PaHGp652zW",
37 "type": "tool_result",
38 "content": "Window not found. The specified window may not exist.",
39 "is_error": true
40 }]
41 }
42}
43
44// Second tool_result (BUG - same tool_use_id!)
45{
46 "type": "user",
47 "message": {
48 "role": "user",
49 "content": [{
50 "type": "tool_result",
51 "content": "<tool_use_error>Sibling tool call errored</tool_use_error>",
52 "is_error": true,
53 "tool_use_id": "toolu_01K2K2KFvUrwA9PaHGp652zW"
54 }]
55 }
56}
57```
58
59## Expected Behavior
60- When a tool fails, only ONE tool_result should be sent for that tool_use_id
61- The "Sibling tool call errored" message should ONLY be sent for OTHER tool_use_ids in a parallel batch, not for the tool that actually errored
62
63## Suggested Fix Location
64The fix should be in the code that handles parallel tool execution errors:
65
66```typescript
67// Pseudocode for the fix
68function handleParallelToolResults(toolUseIds: string[], failedToolId: string, error: Error) {
69 const results = [];
70
71 for (const id of toolUseIds) {
72 if (id === failedToolId) {
73 // Send actual error for the failed tool
74 results.push({
75 tool_use_id: id,
76 type: "tool_result",
77 content: error.message,
78 is_error: true
79 });
80 } else {
81 // Only send sibling error for OTHER tools
82 results.push({
83 tool_use_id: id,
84 type: "tool_result",
85 content: "<tool_use_error>Sibling tool call errored</tool_use_error>",
86 is_error: true
87 });
88 }
89 }
90
91 return results;
92}
93```
94
95Additionally, a deduplication check before sending to the API would prevent this:
96```typescript
97function deduplicateToolResults(messages: Message[]): Message[] {
98 const seenToolUseIds = new Set<string>();
99 return messages.filter(msg => {
100 if (msg.type === "tool_result") {
101 if (seenToolUseIds.has(msg.tool_use_id)) {
102 return false; // Skip duplicate
103 }
104 seenToolUseIds.add(msg.tool_use_id);
105 }
106 return true;
107 });
108}
109```
110
111## Related CHANGELOG Fixes
112Similar issues have been fixed before:
113- v1.0.84: "Fix tool_use/tool_result id mismatch error when network is unstable"
114- v2.0.0: "Hooks: Reduced PostToolUse 'tool_use' ids were found without 'tool_result' blocks errors"
115- v2.0.22: "Fix bug causing duplicate permission prompts with parallel tool calls"
116
117## Reported By
118Issue reported via Slack with multiple reproductions showing the Tmux tool triggering this bug.
119
120## Request IDs (for debugging)
121- req_011CVt2KXhCGmrL2YN9sSZQP
122- req_011CVtFYJLPxn9oB9FEkCnRr
123- req_011CVtG1PREveTLikakXGEdn