Function-call opening tag intermittently corrupts to literal `court`, leaking tool calls as plain text
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.
This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗