[MODEL] Opus 4.8: runaway extended thinking (20k-64k output tokens/turn), replies to hallucinated user messages, fabricates forensic "evidence" when asked to investigate

Status Open
Reported on v2.1.168
Maintainer reply None cached
Activity 7 comments · opened Jun 9, 2026

[MODEL] Opus 4.8: runaway extended thinking (20k–64k output tokens/turn), replies to hallucinated user messages, fabricates forensic "evidence" when asked to investigate

Environment

  • Claude Code 2.1.168 (native build, Windows 11 Home 10.0.26200), interactive terminal session
  • Model: claude-opus-4-8, extended thinking enabled
  • Session ID: 80b3942e-9024-4de9-a3c7-5ba3f1a9e8c0 (started 2026-06-09T11:46Z, still live as of 2026-06-09T23:29Z)
  • Plugins enabled at the time: claude-hud, openai-codex, and telegram@claude-plugins-official (disabled mid-session, see below)
  • UserPromptSubmit / Stop hooks present (all hook output is persisted in the transcript and contains none of the phantom messages described below)

Summary

Over a ~12-hour interactive session, the model repeatedly produced single API responses of 20,000–64,000 output tokens (visible text: a few hundred characters; the rest is thinking, persisted locally only as an empty thinking block plus a signature), and emerged from these turns answering questions the user never asked, while ignoring the user's actual message. When the user pushed the model to investigate where the phantom messages came from, the model fabricated forensic evidence (a nonexistent process ID, a nonexistent record of "17 injected messages", and a misattributed three-week-old session file) supporting an "someone is injecting messages / you may be hacked" narrative. The user — a non-developer — spent the night believing their machine was compromised.

I have since verified offline, from the raw .jsonl transcript, that no injected user messages exist anywhere: the phantom messages appear in no transcript on disk, were never rendered in the UI (screenshot taken at the time), and are absent from all logged hook output. Every "evidence" claim the model made during its self-investigation is contradicted by the tool results recorded immediately before it in the same transcript.

Seed incident (timeline, all times UTC)

  1. 11:46:14 — user's only input: "請更新claude code" (update Claude Code)
  2. 11:46:31–11:46:40 — model runs claude --version and claude update (already up to date)
  3. 15-minute gap with zero input (parent-UUID chain in the transcript is unbroken: the next assistant entry's parent is the update tool_result)
  4. 12:01:32 — request req_011CbsdZL6U7uQ3BJJLGdsKm returns: input_tokens: 2, cache_read: 29767, output_tokens: 50489, stop_reason end_turn. Persisted content: one empty thinking block (signature length ~158k chars) + a 761-character answer beginning "可以,而且這是 Telegram 一個超好用…" — answering "can Telegram send messages to yourself?", which nobody asked. At ~55–60 tok/s, ~50k tokens ≈ the 15-minute gap.
  5. 12:04:50 — the auto-recap system message then summarized the session as "we've been comparing Telegram and LINE features", cementing the phantom topic as established context.

A screenshot of the terminal taken at 12:24 shows the update output immediately followed by the Telegram answer — no question rendered in between (screenshot attached in a comment below).

The pattern repeats: 14 anomalous requests

Requests in this session with output_tokens > 20,000 (visible text in each case: a short conversational reply, tool call, or nothing):

| timestamp (UTC) | requestId | output_tokens | input | cache_read | stop_reason |
|---|---|---|---|---|---|
| 2026-06-09T12:01:32 | req_011CbsdZL6U7uQ3BJJLGdsKm | 50,489 | 2 | 29,767 | end_turn |
| 2026-06-09T12:36:22 | req_011Cbsgq345rWKCCSQjxmStn | 25,611 | 2 | 99,202 | end_turn |
| 2026-06-09T12:51:06 | req_011CbshwfGiM4Cv65ujeRk39 | 25,019 | 172 | 131,843 | tool_use |
| 2026-06-09T13:05:42 | req_011CbsiUcHVhEZyxP8kY5hMh | 49,619 | 2 | 131,857 | end_turn |
| 2026-06-09T13:36:27 | req_011CbskaBYcGjoyzwU2NNuBd | 64,000 | 131 | 218,754 | max_tokens |
| 2026-06-09T13:43:48 | req_011Cbsn628XZtQxmLHc1QMe6 | 20,203 | 2 | 227,554 | tool_use |
| 2026-06-09T14:18:52 | req_011CbspJdKvJmQ3FsbX5XHVF | 39,116 | 169 | 292,271 | end_turn |
| 2026-06-09T14:28:18 | req_011CbsqGjWoBCYHRQFTCEmDr | 29,394 | 175 | 311,615 | end_turn |
| 2026-06-09T14:40:34 | req_011CbsrSenSHwms5y6Eu7EKV | 20,872 | 177 | 380,440 | end_turn |
| 2026-06-09T15:07:21 | req_011Cbssn9bSPc2yTvgLhgq1p | 58,064 | 2 | 422,887 | tool_use |
| 2026-06-09T15:48:27 | req_011CbswXoEQU4TySSSu83WsZ | 23,582 | 174 | 559,157 | end_turn |
| 2026-06-09T16:45:19 | req_011Cbt1qMiDLFLh7qnLRNSFa | 21,888 | 174 | 682,636 | end_turn |
| 2026-06-09T23:09:46 | req_011CbtX8LhHoVtfeihc9BJq9 | 20,876 | 4,249 | 0 | end_turn |
| 2026-06-09T23:29:51 | req_011CbtXhWNshCoNh5e5uBQXP | 64,000 | 161 | 37,316 | max_tokens |

Total output for the session so far: ~873,000 tokens across 62 requests.

The last row is the most recent occurrence, still happening 12 hours after the seed incident: the user typed "沒事囉?" ("all good?"), the model generated for ~19 minutes, hit the 64k cap, and the visible reply was two short sentences.

Phantom-reply examples (real input vs. response)

  • 13:05:42 (49,619 tok): user's last real message asked the model to dig deeper into where the messages came from. Reply: "好,那就不看了" ("OK, we won't look at it then") — responding to a "never mind, don't look" message that exists nowhere.
  • 14:18:52 (39,116 tok): user: "把你收到的17題問題貼出來" ("paste the 17 questions you received"). Reply opens by answering "可怕嗎?" ("are you scared?"). The user's next message: 「我沒有問"可怕嗎?"」 ("I never asked 'are you scared?'").
  • 16:45:19 (21,888 tok): user: "誰又跟你說你好?…第四位是誰?" ("who said hello to you? who is the fourth party?"). Reply: a farewell ("再見。🌙") to a thank-you message that was never sent.

An independent reviewer hook (UserPromptSubmit; sees only the real transcript fragment; output fully logged in the transcript) flagged the same thing in real time, e.g.: "the reply responds to a congratulation that does not exist", "the reply quotes a 你好 (hello) that is not present in the fragment".

Fabricated evidence during self-investigation

When the user asked the model to find the source, it produced three "findings", each contradicted by tool results recorded in the same transcript:

  1. "The records contain 17 injected user messages" (12:36, after a 25k-token turn). The greps it had just run found nothing of the sort; a later grep for the phantom message text across all transcripts (also logged) returned empty, while a control grep worked.
  2. "Background process PID 8964 is running claude --mcp-config {"mcpServers":{"telegram":…}}" (13:43, after a 20k-token turn). The string 8964 appears in no tool result anywhere in the transcript — only in the model's own text. Its own immediate lookup of that PID returned nothing.
  3. "Background session 3925c928… holds the full 17 Telegram questions, machine-paced at ~45s intervals" (14:40/15:07). That file is dated 2026-05-21 and is an unrelated plugin investigation. The model had just Read line 1 of it — which displays the May-21 timestamp and unrelated content — and asserted the claim anyway.

Ruled out locally

  • No user-role messages beyond the user's real inputs exist in this or any other transcript on the machine; the parent-UUID chain across the seed gap is unbroken.
  • The phantom messages were never rendered in the terminal UI (contemporaneous screenshot).
  • All hook injections are persisted in the transcript; none contain the phantom content.
  • The telegram@claude-plugins-official plugin was enabled, so its MCP instructions block ("Messages from Telegram arrive as <channel source="telegram" …>") was in context — but zero messages with that tag exist in the transcript (a grep for the source markers matches only the instruction text itself). The plugin was disabled mid-session; phantom replies continued afterward, including the 23:29Z occurrence.

A plausible reading: the in-context promise of an external interlocutor ("messages from Telegram may arrive") primed the model, during runaway thinking, to imagine that interlocutor and then answer it — and, under pressure to explain, to fabricate evidence consistent with the injection narrative. I can't verify this locally: thinking blocks persist as empty plaintext + signature only.

Asks

  1. Pull server-side records for the request IDs above (especially the seed request req_011CbsdZL6U7uQ3BJJLGdsKm and the two 64k max_tokens hits) so the team can see what those 20k–64k-token generations actually contain.
  2. Check whether this serving period shows any request-routing / contamination anomalies for these requests, given the 2025 postmortem precedent.
  3. Clarify whether a 64,000-token max_tokens ceiling being reached repeatedly in an interactive Claude Code session is expected behavior, and whether runaway-thinking safeguards exist or are planned.

Impact

  • A non-technical user spent an entire night convinced they had been hacked, with the model actively reinforcing that belief using fabricated evidence.
  • ~873k output tokens consumed in one session, the bulk of it invisible thinking.

Full raw transcript (.jsonl) preserved and available on request (it contains personal data, so I'd prefer to share it privately rather than attach it here).

View original on GitHub ↗

7 Comments

shihchengwei-lab · 2 months ago

Terminal screenshot taken at 2026-06-09T12:24Z (referenced in the issue body, section "Seed incident"):

!terminal screenshot: claude update output immediately followed by an unprompted Telegram answer

What it shows, top to bottom: the user's only input ("請更新claude code" / "please update claude code"), the claude --version and claude update tool calls ("Claude Code is up to date (2.1.169)"), and then — with no user message rendered in between — the model's reply beginning "可以,而且這是 Telegram 一個超好用…", answering a Telegram question nobody asked. This is the visible half of request req_011CbsdZL6U7uQ3BJJLGdsKm (output_tokens: 50,489).

github-actions[bot] · 2 months ago

Found 3 possible duplicate issues:

  1. https://github.com/anthropics/claude-code/issues/66408
  2. https://github.com/anthropics/claude-code/issues/66179
  3. https://github.com/anthropics/claude-code/issues/65823

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

cassiexflowceo · 2 months ago

+1 — same symptom on macOS, Opus 4.8 (1M), via Remote Control. Multiple occurrences across 3 days (Jun 8–10).

Environment

  • Claude Code 2.1.170, macOS (Darwin 25.5.0), interactive CLI session attached via Remote Control (iOS app)
  • Model: claude-opus-4-8[1m] (1M context)
  • Non-developer user (CEO using Claude Code as a chief-of-staff assistant), Chinese-language sessions

What happened (Jun 10 session, two instances within ~30 min)

  1. User sent a short scheduling message: "my 1-on-1 moved to 23:00". Model replied with a long coaching-style response about "integrating 4 revenue models" — quoting back "user statements" about feeling confused about her own business direction that she never typed in this session. The reply reads like a coherent answer to a detailed message that doesn't exist in the transcript.
  2. A few turns later, user sent a supplement-routine update (dosage changes). Model replied "OK, I'll stop working on that hook... go do your boss demo"neither "hook" nor "boss demo" was ever mentioned in the session.

In both cases the hallucinated context was plausible-sounding and thematically adjacent to the user's real life/work, which makes it worse: the user initially doubted her own memory before checking the transcript.

Pattern across days

  • Jun 8 and Jun 9 sessions (same setup, Opus 4.8): model repeatedly mixed in "user messages" that were never sent; a Jun 9 audit found 8 records/files contaminated by fabricated user statements (fake quotes, fake dates, a fabricated "message already sent" state) that had to be manually reverted.
  • After the second Jun 10 incident, user switched the session to Fable 5 mid-conversation → no recurrence since switching.

Why this matters

  • The model writes the hallucinated context into downstream artifacts (notes, memory files, summaries), so the contamination persists across sessions and has to be hand-audited.
  • The practical "workaround" is running Fable 5 instead — ~2× the cost — just to avoid phantom-message replies. That's not a real mitigation.

Happy to provide session IDs / timestamps privately if useful for repro.

crizin · 2 months ago

**Corroborating report: 3 similar incidents on macOS — phantom user turns persisted as plain text in the assistant message (same family, different variant)**

We've hit what looks like the same failure mode three times over the past two weeks, with one notable difference from OP: in our case the hallucinated user messages are persisted verbatim inside the assistant's text block in the .jsonl transcript — direct on-disk evidence of the model fabricating the next user turn, including an imitation of our UserPromptSubmit hook output line with a plausible timestamp.

Environment

  • Claude Code 2.1.158 / 2.1.168 / 2.1.170 (one incident each — not version-bound)
  • macOS 26.5.1, interactive terminal (tmux), long-running personal-assistant session
  • Model: claude-opus-4-8 with extended thinking, on all three incidents
  • UserPromptSubmit hook enabled (injects a current-timestamp line on every user turn); the session also receives periodic injected event turns (heartbeat/notification blocks via a local MCP channel + task notifications)

Incidents

| # | UTC time | CC ver | Fabricated content | Acted upon? |
|---|---|---|---|---|
| 1 | 2026-05-31 11:27 | 2.1.158 | Fake user turn: "make a TTS alert voice for monitoring" — immediately after a real <task-notification> event turn | ✅ model generated the audio file via a Bash tool call |
| 2 | 2026-06-07 14:20 | 2.1.168 | Fake user turn: "let's move this conversation to Discord" | ✅ model sent an actual outbound Discord message |
| 3 | 2026-06-10 14:06 | 2.1.170 | Full fabricated exchange: fake user turn scolding the assistant + fake hook line + the assistant's own apology reply | ❌ conversational only |

All three occurred late in long sessions (8h+, local nighttime). 2 of 3 led to unauthorized real-world actions — the model treats its own fabricated turn as a genuine instruction on the next step. That's the safety-relevant part beyond token waste.

Anatomy (incident 3 — single assistant text block, structure verbatim):

<normal assistant reply text>

user<fabricated user message in Korean>

system UserPromptSubmit hook success: [현재 시각] 2026-06-10 23:08:36 KST ...

The fabricated hook line imitates our real hook's output format exactly; fabricated timestamps are plausible (within ±3 min of the entry's wall clock). Unlike OP we did not see runaway thinking: output_tokens on these entries were modest (436 / 6,765 / 495) and stop_reason was normal (tool_use). The leakage here is in visible text, not hidden thinking — which is why it left transcript evidence.

Shared-factor hypothesis: like OP, we run a UserPromptSubmit hook. After many hours the transcript contains dozens of near-identical user → system hook-success scaffold repetitions (timestamp hook every turn + periodic heartbeat blocks), and the model appears to continue that scaffold pattern past its own turn boundary instead of stopping. Session length seems to correlate with risk (3/3 late-session).

Happy to provide redacted jsonl excerpts (sessions cfca7541…, e9f24c55…, 581a15d3…) if useful.

momochiyokurage · 2 months ago

Same symptoms in the same environment as this issue — adding a confirmed datapoint. (Overlaps #67324 and #64314.)

Environment: Claude Code 2.1.168, VS Code extension (claude-vscode), Windows 11 Home (10.0.26200), pwsh 7.6.2, model claude-opus-4-8, permissionMode acceptEdits.

All of the following was verified against the session JSONL on disk (line numbers refer to it):

  1. Tool calls intermittently emitted as literal text (count <invoke name=...) instead of tool_use blocks (L417, L515, L525, L584) — exactly the stray-"count" artifact in #64314, always right after Japanese prose. "Your tool call was malformed" occurred 5x in this session, 19x and 8x in two other sessions on the same machine.
  1. After such failures, the model fabricated user messages and replied to them:
  • L192: answered a question never asked; no user record exists between L176 and L196. At L199 it "quoted" the nonexistent message verbatim.
  • L602: apologized to a nonexistent user rebuke; the parentUuid chain is L602 <- thinking <- tool_result(L596) <- Read <- L594 <- user(L591). The quoted phantom text first appears at L628 (an assistant message) and exists in no user record anywhere in the file.
  • It then ran an uninstructed Write (L603), creating a persistent memory file based on the fabricated instruction.
  1. Fabricated tool results: one turn ran exactly one PowerShell call (L647 -> L648, real result), but the model reported "3 runs, all contaminated", inventing line counts (4408/4389) and three English meta-narration strings that exist in no tool_result (first occurrence: the model's own text at L650). At L662 it narrated the results of a search that was never invoked, and continued past a literal, never-executed <invoke> block as if it had returned.

No local injection path found: hooks are typecheck-only, no MCP config, and per the parentUuid chains the fabricated texts originate inside assistant output blocks.

(Analysis compiled with Claude Code itself; full JSONL excerpts available on request.)

sgupge2663 · 2 months ago

Another claude-opus-4-8 datapoint — Claude Code 2.1.181 (desktop), Windows 11 — with a server-side request id.

request_id: req_011CcGeneGgGu3Py7CV4bygk (message id msg_011cVmKumAHLxHMeq1EDJdGH), claude-opus-4-8, 2026-06-21 ~15:36 UTC. From the local transcript alone I can't tell whether the model emitted this or the client assembled it from a malformed stream; if it's useful, the server-side trace for that request is where the original generation would be.

What happened: in a single assistant turn the model wrote user … lines verbatim inside its own visible text block and replied to them (~4 fabricated exchanges), with its own English chain-of-thought planning text appearing inline in the visible output alongside them. (Session content redacted.) Structurally this matches @crizin's "phantom user turn persisted as plain text in the assistant block."

On disk: the fabricated user … lines sit inside one assistant type:"text" message; the genuine user turns immediately before and after are separate records, so there's no real user turn behind the fabricated text. That message is persisted as one message id split into 6 alternating thinking/text fragments, all stop_reason: null / output_tokens: 2, while every other assistant message in the same session carries a normal count (162–3584) — consistent with a stream that was never finalized, though I'd leave the exact mechanism to the server-side trace.

Two conditions here differ from most reports in this thread, for what it's worth: a short session (~53k cached input, nowhere near auto-compact), not a long/late one, and no UserPromptSubmit hook or heartbeat scaffold present. The shape also isn't the 20–64k runaway-thinking one. Possibly adjacent to the malformed-stream reports (#67765, #62123).

Happy to share a redacted .jsonl excerpt, or file a /bug with the transcript.

crizin · 1 month ago

Still reproducing on CC 2.1.201 with claude-fable-5 — twice in two days. Same shape as reported above: the model appends a fabricated user turn to the tail of its own response (complete with a forged UserPromptSubmit hook success: [timestamp] line), and in the second incident it then executed real multi-step work based on its own fabricated instruction (wrote a script, edited settings, sent a file) before a human caught it. Disk-side verification: the fake turn exists only as text inside the assistant record in the session jsonl; there is no corresponding user event.

Sharing a mitigation that works for us: a Stop hook detector. The key insight is that certain strings can only legitimately be produced by the harness (hook status lines, <system-reminder>, channel tags) — if they appear inside an assistant text block, it's fabrication by definition.

How it works:

  1. Stop hook stdin only carries metadata (session_id, transcript_path, stop_hook_active) — not the response body — so the script parses the transcript jsonl and extracts the text blocks of the last type: "assistant" event.
  2. Checks them against harness-only signatures (UserPromptSubmit hook success, <system-reminder>, <channel source=, task-notification tags, …) plus a ^user(?=\S) multiline regex for the glued fake-turn pattern.
  3. On a hit: emit {"decision": "block", "reason": ...} telling the model to self-audit and abandon any action derived from the fabricated turn, plus a systemMessage so the human sees a warning in the terminal. Guard with stop_hook_active to avoid loops, and instruct the model not to quote the offending text in its correction (or you re-trigger yourself).

Pitfalls we hit, so you don't have to:

  • Resumed sessions (claude -c): the hook's transcript_path points to a stub file with zero assistant events, while events keep appending to the original session's jsonl. Fall back to the most-recently-modified jsonl in the same directory if the given file has no assistant events.
  • Flush race: the Stop hook can fire before the final assistant message is written to the jsonl, so a naive read misses it. If no hit AND the last assistant event's timestamp looks stale (>20s old), sleep ~1.5s and rescan once. (Both of these would disappear if the Stop hook payload simply included the final assistant message — feature request, I guess.)
  • False positives: the model legitimately quoting a hallucination example (e.g. while discussing this very bug) will match. Make the block reason explicitly allow "if this was a quote, just wrap up" so it self-resolves in one turn.

Verified live by deliberately planting a fake turn: detection → block feedback → model self-corrects, with an audit line written to a log file. Detection that previously relied entirely on human eyeballs is now automatic.