tool-call markup malformation (`antml:` namespace prefix drop) silently drops tool calls in long Opus-class sessions

Open 💬 0 comments Opened Jun 20, 2026 by tomoyuki-nezu

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:

  1. Garbage-token prefix (unambiguous): a stray token is prepended to the opening tag —

``
court <invoke name="Bash"> ...
`
instead of the well-formed
antml:`-namespaced opening tag.

  1. Bare (namespace-less) tag (secondary signal): the antml: prefix is dropped from invoke / parameter / function_calls tags, 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, PreToolUse never 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 Stop hook's only outputs are {decision, reason} (block + inject text for the next turn) or allow-stop. It cannot synthesize and execute a tool_use on 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)

  1. Generation-side: reduce the prose→tool namespace-prefix slip on Opus long-context (the root cause).
  2. 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.
  3. 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._

View original on GitHub ↗