[Fix] Bug fix for API 400 error "`tool_use` ids must be unique"

Status Closed — not planned
Reported on v2.0.76
Maintainer reply None cached
Activity 4 comments · opened Jan 24, 2026 · closed Feb 28, 2026

Bug Description

(This is for v.2.0.76, but v.2.1.19 has exactly the same bug)

The QS function (line 482734) is supposed to slice messages from a compaction boundary:

function QS(A) {
  let Q = I97(A);
  if (Q === -1) return A;  // BUG: Returns same reference!
  return A.slice(Q);
}

I97 searches for compact_boundary messages. When there's no compaction:

  • I97 returns -1
  • QS returns A directly without creating a copy

How This Causes Duplication

  1. qe2 starts with mA = [...V] (copy of mutableMessages)
  2. qe2 calls ew({ messages: mA })
  3. ew creates F = QS(mA) - but F === mA (same reference!)
  4. ew makes API call, receives streaming response
  5. Streaming yields partial message P1 (with tool_use)
  6. ew accumulates P1: L.push(P1), yields P1
  7. qe2 receives P1: mA.push(P1) - mA now has P1, and since F === mA, F also has P1!
  8. ew recursively calls itself with:

``javascript
yield* ew({
messages: [...F, ...L, ...N],
});
``

  1. At this point:
  • F = mA = [original..., P1, ...]
  • L = [P1, ...]
  • P1 appears in BOTH F and L!
  1. Inner ew -> zHA -> SW9 -> GJ normalizes messages
  2. GJ finds two messages with same message.id, merges with e27
  3. e27 concatenates content arrays: duplicate tool_use blocks!

Proposed Fix

// Before
if (Q === -1) return A;

// After
if (Q === -1) return [...A];

One-character fix: always return a copy!

Environment Info

  • Platform: linux
  • Terminal: kitty
  • Version: 2.0.76
  • Feedback ID: 82a1446e-9fb5-4c89-8018-1e45ea46dde1

View original on GitHub ↗

This issue has 4 comments on GitHub. Read the full discussion on GitHub ↗