Function-call opening tag intermittently corrupts to literal `court`, leaking tool calls as plain text

Resolved 💬 1 comment Opened Jun 3, 2026 by koichitas Closed Jun 3, 2026

Summary

Intermittently, an assistant turn that should emit a tool call instead emits the opening
function-call wrapper as the literal string court
(namespace prefix missing), while the inner
<invoke>...</invoke> block is emitted intact as plain text. The harness cannot parse it, so
the tool never runs and control returns to the user mid-task.

  • Claude Code version: 2.1.161
  • Model: Claude Opus (claude-opus-4-8)
  • Platform: Linux (WSL2)

Observed output (verbatim from session log, paths redacted)

さっそく確認します。

court
<invoke name="Bash">
<parameter name="command">timeout 110 node ./scraper.mjs ...</parameter>
<parameter name="description">(some shell command)</parameter>
</invoke>

Only the outer opening tag is corrupted (→ court); <invoke>, <parameter>, and the
closing tags are all correct.

Quantified from local session logs

Scanned 16 sessions / 2071 successful tool_use blocks:

  • 11 leaked tool calls, overall rate 0.53%.
  • All 11 occurred in a single session (intra-session rate ≈ 10%, lines 411–541 of 548).
  • The corrupted string is always exactly court (deterministic, not random garbage).
  • 100% of leaks were preceded by preamble prose in the same turn.
  • All in the latter half of a long session (500+ lines / many prior tool calls).

The deterministic substitution to court looks like a token-level confusion of the
function-call opening special token, not random sampling noise.

Reproduction

The initial corruption is not reliably reproducible on demand (≈0.5% baseline). But the
recurrence is reproducible via in-context conditioning. Controlled experiment (Opus 4.8,
5/5/3 runs):

| Condition | leak rate |
|---|---|
| Control: short fresh session, normal tool requests | 0 / 5 runs |
| Quoted poison: the court\n<invoke> example shown as quoted text in the user prompt | 0 / 5 runs |
| Resumed poison: resume a real long session (548 lines) whose history already contains court\n<invoke> assistant turns, then ask for a trivial echo | 1 / 3 runs (~33%) |

Takeaways:

  • Merely seeing the pattern as quoted text does not induce it.
  • Resuming a long session that already contains corrupted court\n<invoke> assistant turns

reproduces the corruption ~1/3 of the time even for a trivial tool call → the model appears to
condition on its own prior corrupted token stream (in-context self-poisoning), amplified by long
context. This explains the single-session clustering: once it happens, the session keeps
re-leaking.

Impact / workaround

Work is interrupted mid-task. Because the <invoke> block is intact, the intended call is
100% machine-recoverable from the leaked text (we wrote a small parser that reconstructs it),
and the practical user workaround is to start a fresh session rather than continue the poisoned
one. But the real fix is model-side: stop emitting court for the function-call opening tag.

Happy to share the anonymized 11-sample corpus and the detector/recovery scripts if useful.

View original on GitHub ↗

This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗