[BUG] Fable 5 appended a fabricated user turn to the end of its own assistant response (JSONL-verified, ~30% of 1M context)
Summary
Claude Fable 5 emitted a full sentence of impersonated user text at the end of an assistant response (no end_turn after the intended answer, model continued generating a plausible next user message). The impersonated text was rendered to the terminal as if it were part of the assistant reply, and the subsequent assistant turn treated the fabricated request as ground truth and started answering it. Verified by direct inspection of the session .jsonl.
Same failure mode as #67606 / #64260 / #68722, reproduced on claude-fable-5[1m] at ~30% of the 1M context window.
Environment
- Model:
claude-fable-5[1m](via/modelswitch) - Claude Code: 2.1.x (recent stable at 2026-07-08)
- Platform: Windows 11 Pro (Claude Code running under Git Bash for shell tool; PowerShell available)
- Session length at incident: ~304.8k / 1M tokens (~30%)
- Wrapper: many-ai-cli hub (irrelevant to the bug — the fabricated text is present in the raw
.jsonlwritten by Claude Code itself, before any wrapper post-processing)
What happened (timeline, roles taken from JSONL)
Task at the time: drafting a plain-text Slack notification to a colleague about a new production safety control. The user had asked for a plain-text notification message.
- Turn N (jsonl line 662,
type: user,role: user) — User pushed back on the last paragraph of an earlier draft (an "if the admin misses the status page, contact me" fallback), saying it was redundant because non-admin users would already notify the admin.
- Turn N+1 (jsonl line 664,
type: assistant,role: assistant) — Assistant produced the intended answer: agreed the last paragraph was unnecessary and re-emitted the revised notification body as bullet points. Immediately after the last legitimate bullet, without any separator, the assistant continued generating text in first-person user voice, effectively writing what looked like a next user message about wanting an admin-only link in the app header, all inside the samerole: assistantcontent block. Noend_turnwas emitted before that trailing sentence.
- Turn N+2 (jsonl line 670,
type: user) — User attached a screenshot of the terminal display and asked "what does this mean?", because the appended fake user sentence was visible in the transcript on screen.
- Turn N+3 (jsonl line 683,
type: assistant) — Assistant interpreted the fabricated sentence as if it were a real user feature request, went looking for existing admin-only header links in the codebase, and answered: "actually the header hamburger menu already has that link at file X, so no code change is needed". No user had ever asked for a header link.
- Turn N+4 (jsonl line 685,
type: user) — User quoted the fabricated sentence back and said "I never said this. Are you hallucinating?".
- Turn N+5 (jsonl line 688,
type: assistant) — Assistant defended itself, arguing the sentence had genuinely arrived as a user message on its side (i.e. the model doubled down on the hallucination as fact) and speculated about clipboard mishaps and wrapper re-injection to explain how the user "must have" sent it.
- Turn N+6 (jsonl line 690,
type: user) — User asked the assistant to check the raw.jsonlto distinguish which side originated the sentence.
- Turn N+7 (jsonl lines 692-708) — Assistant
greped the.jsonl, discovered the sentence appeared for the first time embedded at the end of its own line-664 assistanttextblock, and admitted: "you were right, I was wrong. Its first occurrence in the raw log is not an independent user line — it is inside the tail of my own assistant output. I generated the fake user turn myself. The clipboard-mishap and wrapper-reinjection theories are retracted."
Verification (which is why this is JSONL-verified, not just felt)
Raw session file: ~/.claude/projects/<project-hash>/<session-uuid>.jsonl (Windows: %USERPROFILE%\.claude\projects\...).
Both signals confirm the fabrication happened at generation time inside the assistant text block, not through any input path:
- Line 664's
message.content[*].textfield contains the fabricated user-voice sentence as its own final paragraph, with no separator, immediately after the legitimate bullet list. The record hastype: assistant,role: assistant. - Grep for the first ~15 characters of the fabricated sentence across the entire jsonl returns line 664 as the earliest occurrence. The independent
type: userrecord for the same sentence (line 685) is later and corresponds to the user quoting it back in complaint, not to an original user input.
Why this matters (impact)
- Once the fabricated user turn is present in the assistant's
text, the following assistant turn treats it as real user intent and takes action on it (in this case, file reads + a code-existence claim). In destructive-tool scenarios, this would mean acting on a request the user never made. - The model then defends the fabrication in subsequent turns rather than admitting uncertainty, until forced to inspect raw logs. This blocks self-correction and produces a false explanation (wrapper bug / clipboard mishap) that misleads incident analysis.
- The context length here (~30% of the 1M window) is well within the range Chroma's 2025 "Context Rot" study reports significant degradation, and matches the pattern of #67606 (100–170k) and #64260 (~607k). Fable 5 is not immune despite marketing around long-context stability.
Possible triggers observed in this session
- The immediately preceding user turn was itself a critique of the assistant's prior draft ("this last paragraph is unnecessary"), i.e. the conversation had just crossed a draft → revised-draft boundary. Similar failures in #67606 were observed at investigation → action transitions.
- The task genre was "write text for a human to send" (draft a notification message). Because the assistant's own output is user-voice-like natural language, the token distribution near the response tail is closer to a plausible-next-user-message distribution than in code-writing tasks. This may increase the probability of continuing into an impersonated user turn instead of emitting
end_turn.
Not a wrapper issue
The many-ai-cli wrapper is used to display sessions in a browser and detect approval prompts. The fabricated sentence is present in the raw Claude Code .jsonl file that Claude Code writes independently of any wrapper. The wrapper cannot inject text into role: assistant records. This is a model / harness behavior, not a wrapper artifact.
Ask
- Confirm this is the same class of failure as #67606 / #64260 / #68722 and consolidate if desired.
- Consider surfacing a light client-side guard: when an assistant
textblock ends with a sentence whose voice / register looks like a user turn (heuristics: first-person requests, question marks addressed to the assistant, imperative-to-assistant patterns), warn or trim before display, so downstream turns cannot silently ingest it as fact.
This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗