-
-
Notifications
You must be signed in to change notification settings - Fork 69.5k
Fix: tool_use_id mismatch error causes infinite loop instead of recovery #44473
Description
Bug Description
When the Anthropic API rejects a request due to a tool_use/tool_result mismatch error:
LLM request rejected: messages.156.content.2: unexpected tool_use_id found in tool_result blocks: toolu_01YMCQha57tDp359ZestPfwU. Each tool_result block must have a corresponding tool_use block in the previous message.
The error is formatted and sent to the user as a reply, but no recovery is attempted. When the user responds, the same broken conversation history is sent again, causing the same error — resulting in an infinite loop of the same error message.
Root Cause
formatAssistantErrorText()catches the error via the genericinvalid_request_errorregex- Returns
"LLM request rejected: <message>"as user-facing text - No special handling exists to suggest
/newor attempt transcript repair - User replies → same broken history → same error → loop
The existing repairToolUseResultPairing() runs on context build but the mismatch persisted, suggesting an edge case in the repair logic or timing.
Proposed Fix
Add detection for tool_use/tool_result mismatch errors alongside the existing role ordering error handling:
1. In errors.js - formatAssistantErrorText() (after line ~255):
// Catch tool_use/tool_result mismatch errors (transcript corruption)
if (/tool_use_id|tool_result.*corresponding.*tool_use|unexpected.*tool.*block/i.test(raw)) {
return ("Conversation history corruption detected. " +
"Please use /new to start a fresh session.");
}2. In errors.js - sanitizeUserFacingText() (after role ordering check):
Same pattern added for consistency.
3. In run.js - promptError handler (after role ordering check ~line 333):
// Handle tool_use/tool_result mismatch errors (transcript corruption)
if (/tool_use_id|tool_result.*corresponding.*tool_use|unexpected.*tool.*block/i.test(errorText)) {
return {
payloads: [
{
text: "Conversation history corruption detected. " +
"Please use /new to start a fresh session.",
isError: true,
},
],
meta: {
durationMs: Date.now() - started,
agentMeta: {
sessionId: sessionIdUsed,
provider,
model: model.id,
},
systemPromptReport: attempt.systemPromptReport,
error: { kind: "tool_result_mismatch", message: errorText },
},
};
}Impact
- Before: User sees repeated raw API error, no way to escape except manually running
/new - After: User sees actionable message on first occurrence, loop is broken
Additional Notes
A more robust fix would be to attempt automatic transcript repair when this error is detected (calling repairToolUseResultPairing() and retrying), but the user-facing message is a safe fallback that prevents the loop.