claude-opus-4-8: malformed tool-call wrapper (raw <invoke> XML leaks as text, tool call fails) + off-topic/hallucinated replies since ~2026-06-26

Status Open
Reported on v2.1.187
Maintainer reply None cached
Activity 5 comments · opened Jun 28, 2026

Environment

  • Claude Code desktop app (entrypoint claude-desktop), updated to latest; bundled claude-code 2.1.187. Bug persists after updating.
  • Windows 11 (10.0.26200)
  • Model: claude-opus-4-8 (used in all sessions)
  • Endpoint: https://api.anthropic.com (official, no proxy)
  • Reasoning effort: high (extended thinking on)

Summary

Since ~2026-06-26/27, claude-opus-4-8 intermittently produces two coupled failures:

  1. Malformed tool calls. Instead of a structured tool_use block, output is stored as a single plain text block containing raw tool-call XML (a stray token court followed by <invoke name="..."><parameter ...>...</invoke>). No tool_use block is produced, so the client has nothing to execute → the tool call fails and the raw XML is shown verbatim in the conversation.
  2. Off-topic / hallucinated replies including content the user never said (context confusion).

Evidence (session transcript .jsonl)

  • Leaking assistant message: stop_reason = "tool_use" but message.content is a single text block with NO tool_use block; text contains literal `court

<invoke name="Write">...</invoke>. model = claude-opus-4-8`.

  • The wrapper that should be <function_calls> appears corrupted as court.

Onset & frequency

  • Clean before ~06-26 (only one occurrence on 06-17, in an extreme 13,410-line / 1,539-thinking-block session).
  • Frequent on 06-27 and 06-28, including moderate sessions (~1,100–1,400 lines). Intermittent within a session; worse in longer/heavier sessions and with large tool payloads (Write/Workflow content).

Ruled out

  • Client version: updating the desktop app to latest did NOT fix it.
  • User config: settings.json clean (no hooks, output styles, or injected system prompt).
  • Project/data: no <invoke> text anywhere in the repo; local headless claude -p executes tools normally.

Workaround

  • Switching the model from Opus 4.8 → Opus 4.7 (same session, same machine) immediately restores correct tool execution AND coherent on-topic replies. Strongly indicates a claude-opus-4-8 server-side regression.

Impact

Severe: tool calls fail and work is blocked; off-topic replies waste turns. Had to abandon Opus 4.8 and fall back to 4.7.

View original on GitHub ↗

5 Comments

github-actions[bot] · 2 months ago

Found 3 possible duplicate issues:

  1. https://github.com/anthropics/claude-code/issues/68354
  2. https://github.com/anthropics/claude-code/issues/70544
  3. https://github.com/anthropics/claude-code/issues/71487

This issue will be automatically closed as a duplicate in 3 days.

  • If your issue is a duplicate, please close it and 👍 the existing issue instead
  • To prevent auto-closure, add a comment or 👎 this comment

🤖 Generated with Claude Code

yurukusa · 2 months ago

Your transcript-level evidence nails the client-side half of this, and it points to the part that's actually dangerous, which I'd flag loudly: this is a silent no-op that looks like success.
When stop_reason = "tool_use" but message.content is a single text block with the raw <invoke …> XML and no tool_use block, the client has nothing to execute — so the tool did not run. But the model's surrounding prose will usually still say "I've written the file / made the change," and the leaked XML scrolls past. So for a Write/Edit/Workflow payload that leaks this way, the file was never written even though the turn reads as if it succeeded. That's the same silent-success-failure class as the fabricated/unexecuted tool-call reports (this looks related to #68354 / #70544, and to the broader "model narrates a tool result that never happened" pattern).
Practical takeaway while it's unfixed server-side:

  • Verify, don't trust the prose. After any session where you saw a stray court + raw <invoke> leak, check that the files/edits actually exist on disk (git status, timestamps, re-open the file). Don't assume the Write landed. A leaked Write is the high-stakes case — it's data you think you saved and didn't.
  • Treat a visible raw <invoke> block as a hard signal to re-issue that step, not continue — the model may keep building on a file state it believes exists.

On reducing the trigger rate (your onset data — frequent since ~06-26, worse in long/heavy sessions, large Write/Workflow payloads, extended thinking on — lines up with a context/thinking-pressure failure mode):

  • Lower or disable extended thinking for tool-heavy work: MAX_THINKING_TOKENS=8000 (or off) for sessions that do a lot of Write/Workflow. The leak correlating with high reasoning effort + large tool payloads suggests the wrapper corruption surfaces under thinking+big-output pressure.
  • Keep sessions shorter around big writes/clear or /compact before a large Write/Workflow step so the tool call is emitted with less accumulated context.
  • Chunk large payloads — splitting a giant Write/Workflow body into smaller writes reduces the per-call output size that seems to correlate with the corruption.

None of these are a fix (the malformed wrapper is model/server-side, and as you confirmed, updating the client doesn't help) — they just lower the probability and, more importantly, the verify-after habit stops a leaked Write from quietly costing you work.

chapayevdauren · 2 months ago

the same issue

zhenweilai · 1 month ago

Sharing forensic data that may help narrow this down. Ran a full scan of local session logs (~/.claude/projects/**/*.jsonl) covering ~2 months (2026-05 to 2026-07), ~122k assistant messages across several models on the same client install, looking for text blocks containing literal <invoke name=...> markup (missing the antml: namespace prefix) where stop_reason was still tool_use.

Model correlation is very strong — this looks opus-4-8-specific, not client/version-specific:

| Model | assistant messages | leaks |
|---|---|---|
| claude-opus-4-8 | 95,086 | 54 (100% of all leaks) |
| claude-fable-5 | 13,503 | 0 |
| claude-opus-4-7 | 9,365 | 0 |
| claude-haiku-4-5 | 2,467 | 0 |
| claude-sonnet (4-6 / 5) | 1,489 | 0 |

54/54 leaks landed on opus-4-8; zero across ~28k messages on other models in the same window, same client, same local config. If the leak rate were model-independent, ~12 leaks would be expected on the other models given their traffic share — none occurred.

Ruled out as causes (tested directly against the data):

  • Client version: reproduces across 2.1.165 → 2.1.205 (6+ versions)
  • Context size: leaks occurred from 41k to 455k tokens with no correlation by bucket; smallest reproduction was message #12 of a brand-new session
  • Prior contamination: in every leak session, no <invoke> text existed anywhere earlier in the transcript — it originates fresh in a single generation, it isn't "learned" from earlier context
  • Local plugins/hooks/settings: no correlation across config changes over the window

Consistent fingerprint across all 54 cases: the malformed message contains only a text content block (no proper tool_use block), yet the API still reports stop_reason: tool_use for that turn — the stop-token signaling still "knows" a tool call was intended, but the call envelope itself got serialized as plain text without the antml: prefix. All 54 occurred immediately after a thinking block, right at the prose→tool-call boundary, several with a stray one-word fragment just before it (e.g. "call" / "count" / "mark" in our transcripts — similar to the "court" token reported elsewhere in this issue family).

Timing: weekly leak rate (per 1k opus-4-8 messages) sat around 0.0–0.3 through late June, dropped to ~0 for five straight days (Jul 2–6), then jumped to ~5–21/1k on Jul 7–10 — a sudden burst with no corresponding local change on our end. That lines up with #75740's "regression, ~1 week" timestamp (filed Jul 8).

Given the clean model-only correlation plus the "text-block-with-stop_reason:tool_use" fingerprint, this reads as a generation-time issue on the opus-4-8 serving path rather than client-side parsing — consistent with the area:model labeling already here and on #69529/#72015.

Happy to share the aggregation script or raw per-incident stats if it's useful for triage.

ChungaChanga-dev · 23 days ago

@chengchangli — the elimination here is what makes this one stand out: client updated, settings clean, no <invoke> anywhere in the repo, headless claude -p fine — everything held constant except the model, and 4.7 fixed it instantly in the same session.

This has been open six weeks now — are you still pinned to 4.7, or did you move back up at some point?