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

Resolved 💬 4 comments Opened Jan 24, 2026 by janbam 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 ↗