diff --git a/.github/issues/duplicate-tool-result-bug.md b/.github/issues/duplicate-tool-result-bug.md new file mode 100644 index 00000000..f8bb83f1 --- /dev/null +++ b/.github/issues/duplicate-tool-result-bug.md @@ -0,0 +1,123 @@ +# Bug Report: Duplicate tool_result blocks with same tool_use_id + +## Summary +When 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: + +``` +API Error: 400 +{"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"}} +``` + +## Root Cause +The 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. + +## Reproduction +1. Execute a tool call that will fail (e.g., Tmux select-pane on a non-existent window) +2. Observe two tool_result messages being generated: + - First: The actual error result ("Window not found...") + - Second: A "Sibling tool call errored" message with the SAME tool_use_id + +## Example JSON (from reported incident) +```json +// Assistant requests tool use +{ + "type": "tool_use", + "id": "toolu_01K2K2KFvUrwA9PaHGp652zW", + "name": "Tmux", + "input": {"args": ["select-pane", "-t", "test-perms3:0.0"]} +} + +// First tool_result (correct - actual error) +{ + "type": "user", + "message": { + "role": "user", + "content": [{ + "tool_use_id": "toolu_01K2K2KFvUrwA9PaHGp652zW", + "type": "tool_result", + "content": "Window not found. The specified window may not exist.", + "is_error": true + }] + } +} + +// Second tool_result (BUG - same tool_use_id!) +{ + "type": "user", + "message": { + "role": "user", + "content": [{ + "type": "tool_result", + "content": "Sibling tool call errored", + "is_error": true, + "tool_use_id": "toolu_01K2K2KFvUrwA9PaHGp652zW" + }] + } +} +``` + +## Expected Behavior +- When a tool fails, only ONE tool_result should be sent for that tool_use_id +- 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 + +## Suggested Fix Location +The fix should be in the code that handles parallel tool execution errors: + +```typescript +// Pseudocode for the fix +function handleParallelToolResults(toolUseIds: string[], failedToolId: string, error: Error) { + const results = []; + + for (const id of toolUseIds) { + if (id === failedToolId) { + // Send actual error for the failed tool + results.push({ + tool_use_id: id, + type: "tool_result", + content: error.message, + is_error: true + }); + } else { + // Only send sibling error for OTHER tools + results.push({ + tool_use_id: id, + type: "tool_result", + content: "Sibling tool call errored", + is_error: true + }); + } + } + + return results; +} +``` + +Additionally, a deduplication check before sending to the API would prevent this: +```typescript +function deduplicateToolResults(messages: Message[]): Message[] { + const seenToolUseIds = new Set(); + return messages.filter(msg => { + if (msg.type === "tool_result") { + if (seenToolUseIds.has(msg.tool_use_id)) { + return false; // Skip duplicate + } + seenToolUseIds.add(msg.tool_use_id); + } + return true; + }); +} +``` + +## Related CHANGELOG Fixes +Similar issues have been fixed before: +- v1.0.84: "Fix tool_use/tool_result id mismatch error when network is unstable" +- v2.0.0: "Hooks: Reduced PostToolUse 'tool_use' ids were found without 'tool_result' blocks errors" +- v2.0.22: "Fix bug causing duplicate permission prompts with parallel tool calls" + +## Reported By +Issue reported via Slack with multiple reproductions showing the Tmux tool triggering this bug. + +## Request IDs (for debugging) +- req_011CVt2KXhCGmrL2YN9sSZQP +- req_011CVtFYJLPxn9oB9FEkCnRr +- req_011CVtG1PREveTLikakXGEdn