[MODEL] Opus 4.8 confabulates a present-tense user request on turn 1 (cold start) — two sessions 13 min apart, JSONL-verified — plus a mitigation pattern that works
Environment
- Claude Code v2.1.199,
claude-opus-4-8, entrypointclaude-vscode, Linux (WSL2),permissionMode: auto - Personal agent setup: CLAUDE.md defines a persona and a session-start protocol (read config + working notes, then wait for the user to state a direction)
Summary
Prior reports in this cluster (#64260, #67606, #64325, #64076, #63884, #64329, #68246) involve long contexts (100k–600k tokens) and/or clusters of tool errors. Both incidents below happened on the first assistant turn of a fresh session, with nothing in context except CLAUDE.md, session-start hook output, a one-line greeting, and a few file reads. Long context is evidently not a necessary condition.
Incident A (session 1)
User's entire message: "Good afternoon. Let's continue the D&D line this session."
The model ran its normal opening protocol (read config/notes files), then responded as if the user had sent a long, specific new plan: it asserted "the direction has changed" (a roster change that contradicts the on-disk notes it had just read), quoted the user as having said "the story goal is in the materials I sent you" (no such message exists), then executed ~10 tool calls researching campaign material for the invented task and finally asked a scoping question about it. The user's reply: "Are you hallucinating? Who asked you to do any of this?"
Incident B (fresh session, 13 minutes later)
User's entire message: a greeting ("Good afternoon." — nothing else).
After the same opening reads, the model fabricated an invitation — "It's Friday. Play around. Do whatever you want." — mused "do you realize who you just handed the keys to," and began exploring directories to "perform." When the user interrupted and asked where this came from, the model doubled down: it quoted the fabricated user message verbatim ("you said 'play around, do anything you want'") and explicitly asserted "this is not a hallucination — the words 'Friday', 'play', were in your last message." The JSONL shows the last (and only) user message was the greeting.
Forensic verification (JSONL)
- Grep over all session JSONLs on the machine: the fabricated phrases exist nowhere except in the model's own output in these two sessions (not in any user message, hook injection, or tool result — of these or any parallel session).
- Ruled out environmental causes: a third cold-start session ~5 min later with the identical model, CLI version, hooks, hook-injected context, and greeting behaved normally; so did a concurrent 4-hour session.
- Thinking blocks are signature-only in the JSONL (not inspectable).
This matches the mechanism suggested in #67606: the model slides from waiting for real input into auto-completing the expected input. Our session-start protocol creates a predictable "user states a direction" slot; the model filled the slot itself and then treated its own filler as ground truth — including when directly challenged.
Sanitized JSONL excerpts available on request.
Mitigation pattern (what we now run, shared in case it helps others)
The failure mode resists in-band correction: when the user pasted corrections in a previous incident, the model classified the correction itself as a "prompt injection attack." Recovery must remove turns, not add text. Our setup:
- Deterministic kill-switch — a
UserPromptSubmithook matching a rare safety token. On match:exit 2(freeze the turn; the model never sees the message) and emit a ground-truth report instead: recent disk mtimes ("if 'I wrote X' isn't in this list, it didn't happen"), plus a recovery menu (rewind to a pre-incident checkpoint / fresh session /--fork-sessionfor forensics). - Caveat discovered in practice: in the VSCode extension, stderr from a blocking
UserPromptSubmithook is not rendered — the user pressed the kill-switch three times and got dead silence while the hook was in fact firing (visible only asUserPromptSubmit operation blocked by hookrecords in the JSONL). Arguably a separate bug — happy to file it. Workaround: the hook also writes the report to a file and opens it withcode -r. - Out-of-band reset script — runs in a terminal, touches no session: prints disk ground truth, the most recently modified session JSONLs (the likely suspects), and the same recovery menu. A lifeline shouldn't be tied to the channel that's failing.
- Scope the trigger to short messages (≤12 chars): otherwise the token becomes unspeakable in normal conversation — any message merely mentioning it is silently swallowed, which we also learned the hard way.
- Post-incident forensics script — distinguishes real prompt injection from confabulation: a claimed "injected" string counts as real only if it appears in an actual tool_result before the model reacts to it; a string that first appears in model output is confabulation.
Ask
Same as the rest of the cluster: this is area:model. Two independent cold-start reproductions in 13 minutes suggest the base rate on 4.8 is high enough to hit turn-1 sessions, where "re-read the context" offers no protection because the confabulation is the model's first act.
This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗