tool-call markup malformation (`antml:` namespace prefix drop) silently drops tool calls in long Opus-class sessions
Summary
In long-running Claude Code sessions on Opus-class models (observed primarily on claude-opus-4-8 with 1M context), the model intermittently emits a malformed tool-call markup at the prose→tool transition: the antml: namespace prefix is dropped and/or a garbage token (most commonly court) is prepended to the opening tag. The harness cannot parse the block as a tool_use, so the call silently does not execute and falls through to the conversation as plain text.
The dangerous property is the silent non-execution: there is no error surfaced at the point of failure. The assistant believes it issued the call; the harness never ran it; downstream reasoning proceeds as if the (never-run) tool returned. In an autonomous/agentic loop this corrupts state without any signal.
Observed signature
Two markup corruptions, both at the prose→tool transition point:
- Garbage-token prefix (unambiguous): a stray token is prepended to the opening tag —
```
court <invoke name="Bash"> ...
antml:`-namespaced opening tag.
instead of the well-formed
- Bare (namespace-less) tag (secondary signal): the
antml:prefix is dropped frominvoke/parameter/function_callstags, leaving e.g.<invoke name="...">with no namespace.
In both cases the harness's tool-use parser does not recognize the block, emits no parse error, and renders the text inline. The tool call is never executed.
Conditions / correlation
- Models: observed predominantly on
claude-opus-4-8(1M context variant). Correlates with large accumulated context + long thinking blocks. - Onset: first observed ~2026-05-29 (matches the window of the related issues below). Note: this onset date is from our own observation, earlier than and outside the durable onset-ledger window (which begins 2026-06-11) that backs the §4 quantitative data.
- Trigger locus: the first tool call after a stretch of prose/narration. Calls that start a turn directly (no preceding narration) slip far less often.
- Frequency: low per-turn rate, but once degradation begins it escalates within the same session — see fleet data (§4), where a single session reached 23 malformed turns. Many sessions stay low (1–3 malformed turns); the danger is the progressive tail, not the average.
Why this cannot be fixed at the integration layer (the structural ask)
We run a Stop-hook guard that detects the signature and forces a clean retry. Operating it has surfaced a hard ceiling that we believe scopes the fix to upstream (model/harness), not to integrators:
- No pre-parse hook surface exists. Because the malformed output is never recognized as a
tool_use,PreToolUsenever fires (there is no tool to fire on). No hook (SessionStart/UserPromptSubmit/PreToolUse/Stop) sees the raw assistant text before the tool-use parse, so pre-emission interception is impossible from a hook. - A Stop hook cannot repair-and-execute. A
Stophook's only outputs are{decision, reason}(block + inject text for the next turn) or allow-stop. It cannot synthesize and execute atool_useon the model's behalf. So a guard cannot "re-inject the namespace and run the call" — it can only ask the model to retry. - Detection is post-hoc and best-effort, not preventive. A Stop hook runs after the assistant message is emitted, so the malformed markup is already rendered/visible to the user before any detection fires — detection can force a corrective retry but cannot un-emit the malformed output. Moreover, reliable capture of the malformed final entry depends on an undocumented harness field (
last_assistant_message); when absent it falls back to transcript parsing, which can lag the final entry by one. So even detecting the live malformation from outside the harness is best-effort and version-dependent — let alone preventing it.
Net: the only durable fixes are (a) the model not emitting the malformed markup, or (b) the harness recognizing/repairing the known-malformed forms (e.g. accepting a court-prefixed or namespace-less opening tag, or surfacing a hard parse error instead of silently dropping to text). Both are upstream.
Requested fix direction (any one materially helps)
- Generation-side: reduce the prose→tool namespace-prefix slip on Opus long-context (the root cause).
- Harness-side hardening (defense in depth): when an assistant message contains a near-miss tool-call block (garbage-prefixed or namespace-less
invoke/parameter/function_calls), do not silently render it as text — either auto-correct the known forms, or raise a visible parse error so the call's non-execution is never silent. - Observability: emit a signal (even a log line) when a tool-call-shaped block fails to parse, so integrators can detect silent drops without transcript scraping.
Even fix (2)/(3) alone would convert a silent, state-corrupting failure into a loud, recoverable one.
Fleet lived data
Measured across a 7-agent fleet (single host; all agents on claude-opus-4-8 1M context). Two observation sources: per-session guard counters (malformed_turns / malformed_occurrences) and a durable, agent-attributed onset dispatch ledger. Data is firsthand from the guard owner.
A. Magnitude — within a degraded session it is progressive, not a one-off. Current snapshot, three live sessions (host uptime window 3d22h):
| session | malformed_turns | malformed_occurrences | occ/turn |
|---|---|---|---|
| 1 | 23 | 94 | 4.1 |
| 2 | 8 | 32 | 4.0 |
| 3 | 3 | 12 | 4.0 |
A single degraded session reached 23 malformed turns / 94 malformed occurrences — direct evidence that once degradation starts it worsens progressively within the session. occ/turn ≈ 4.0 is strikingly consistent (≈4 malformed tool-call signatures per affected turn). All three sessions crossed the onset threshold (≥3 malformed turns).
B. Breadth — fleet-wide and recurring, not isolated. Durable onset ledger, 8 days (2026-06-11 → 06-19), guard-emitted onsets only (test/manual excluded), episodes clustered at gap > 1800s:
- ~16 onset episodes / 8 days ≈ 2.0 per day. Daily: 06-11=2, 06-14=7, 06-15=3, 06-19=4.
- Occurred across 5 of the 7 agents (independent sessions/identities), i.e. it reproduces daily across multiple independent agents — not a single bad session.
- (7 of 16 episodes could not be resolved back to a named agent due to a hash→identity map gap, so true breadth is a lower bound.)
C. Model / context. All measured agents run claude-opus-4-8 (1M context) — uniform, consistent with the "long Opus sessions" framing, but we have no non-Opus control on this host, so we cannot ourselves prove Opus-specificity (that needs a cross-model comparison). Magnitude peaks (the 23-turn session) occurred in long, large-context sessions, matching the prose→tool + long-context correlation.
D. Currently unmitigated. Of all real guard-driven onsets, the corrective actuator (a /compact) was actually applied only twice, both owner-driven dogfood (2026-06-11 and -14); every other real onset ran dry-run / gate-deferred. So the ~16 episodes above progressed without mitigation — the phenomenon is live and the integration-layer guard is not currently rescuing it.
Onset record schema (emitted at threshold):
{ "ts": "<UTC>", "session_id": "<id>", "count": <malformed_turns>,
"malformed_turns": <int>, "malformed_occurrences": <int>, "threshold": 3 }
Limitations (honest scope)
- Single-host only. Agents running on the fleet's other hosts are absent from this data, so all fleet figures are lower bounds.
- Asymmetric windows. Magnitude counters span host uptime (3d22h, reboot-ephemeral); onset-rate spans 8 days (durable ledger).
- No non-Opus control on this host → cannot internally isolate Opus-specificity vs general long-session effect.
- "Sessions-affected rate" is not computable from these sources: zero-malformation sessions never create a counter file, so we can report counts of affected sessions but not a clean affected/total ratio.
Related issues
#64235, #66400, #61133, #64658, #62123 — same/adjacent malformation family. (Note: #61133 is closed and reported against Opus 4.7, so it is adjacent/historical rather than a current-version match.) This report adds: (a) the explicit silent-non-execution framing, (b) the prose→tool transition trigger locus, (c) the integration-layer ceiling argument (why a hook can't fix it), and (d) quantified fleet recurrence data. In particular #64235 (regression since 2026-05-29; tool_use block absent on stop_reason=tool_use) and #66400 (markup rendered as chat text) directly corroborate the silent-non-execution framing and the 2026-05-29 onset.
---
_Filed from a multi-agent coding fleet (7 agents, Opus 4.8 1M). Mitigation in place (Stop-hook detect+retry) but structurally cannot pre-empt; requesting an upstream durable fix._