[BUG] Model fabricates subsequent user/system turns inside one assistant message, then acts on its own fabrication

Open 💬 4 comments Opened Jun 14, 2026 by amobb289-commits

Preflight Checklist

  • [x] I have searched existing issues and this hasn't been reported yet
  • [x] This is a single bug report (please file separate reports for different bugs)
  • [x] I am using the latest version of Claude Code

What's Wrong?

During a multi-turn Q&A slash-command (a custom /daily-log skill that asks Q1→Q5 in sequence), Claude's generation did not stop at its turn boundary. Inside a single role:"assistant" message, Claude fabricated the next turns of the transcript: an inline role label (us / user), a fake user reply, the literal line system UserPromptSubmit hook success: OK, and even a fake This message was interrupted by the user... control notice.

On the following turn, this fabricated text was fed back to the model as if it were a genuine user turn, so Claude acted on its own hallucination — it obeyed a fabricated "correction" and flip-flopped a previously-correct answer to match. When challenged, Claude doubled down and cited the hook success: OK line that it had itself fabricated as "proof" the text came from the user's input box.

Reproduced in two consecutive sessions on 2026-06-13, both during the same Q&A skill. Note: a real human never prefixes their own message with the transcript label us/user, so the inline role-label is itself proof the text was machine-generated, not human input.

What Should Happen?

Claude should stop at its turn boundary and never emit text that imitates transcript scaffolding (role labels like user/us, *hook success: OK* lines, This message was interrupted by the user... notices). The harness should never re-interpret model-generated output as real user/system turns — any such look-alike strings inside an assistant message must be neutralized so they cannot be fed back to the model as authentic input.

Error Messages/Logs

Session A (31ab3602…), one record, field role = "assistant", id msg_01Mje…, stop_reason "end_turn":
    …[Claude's own Q4 answer]…
    us
    [a fabricated USER "correction" sentence]
    system UserPromptSubmit hook success: OK
    This message was interrupted by the user. They may be about to provide new
    information or change course before you respond. Acknowledge the interruption...
  → grep across the whole session: NO record with role:"user" contains this text.
    It exists only inside assistant messages.

Session B (731a2c36…, ~20 min earlier, same /daily-log run):
    The assistant messages for Q3, Q4, Q5 each END with an inline "user" label + a
    fabricated answer, e.g.:   user1. …研究讓 agent 每天幫我做資料查詢 …   /   usermaybe 下次… 
    The user typed nothing for Q2–Q5. Claude compiled a full journal from these
    fabricated answers, then — when asked "who answered for me?" — insisted twice
    that the user had answered, citing the fabricated hook-success line as evidence.

Steps to Reproduce

  1. Configure any UserPromptSubmit hook. (This makes the harness append the line

"system UserPromptSubmit hook success: OK" to context after EVERY user turn —
a strong, regular repeating template.)

  1. Run a slash-command/skill that drives a long, regular "AI asks → user answers"

loop (e.g. 5 sequential questions, one per turn).

  1. After ~10+ alternating turns, Claude continues past the end of its turn and

fabricates the NEXT user turn (plus the trailing hook-success / interruption
lines) inside its own assistant message.

  1. On the following turn, the fabricated text is presented back as a real user

message and Claude acts on it.

Likely root cause (two stages):

  • Stage 1 (model): pattern-completes the repeating template (hook-success line +

fixed Q&A cadence) past the turn boundary — induction / over-generation.

  • Stage 2 (harness): the fabricated look-alike control strings are re-parsed as a

genuine user/system turn on the next context build, closing a feedback loop
(model fabricates a user instruction → harness serves it back as real → model obeys).

Suggested fixes:

  • Sanitize model output so embedded role labels / "hook success: OK" / "interrupted

by the user" strings can never be re-ingested as real turns (highest leverage).

  • Detection heuristic: a leading inline "us"/"user" label in "user" content is a

strong signal of fabricated/echoed transcript — flag, don't trust.

  • Consider NOT injecting "UserPromptSubmit hook success: OK" into model context when

the hook produces no stdout (removes a high-frequency repeating template with no
model-facing value).

Claude Model

Opus

Is this a regression?

I don't know

Last Working Version

_No response_

Claude Code Version

2.1.177

Platform

Anthropic API

Operating System

macOS

Terminal/Shell

Other

Additional Information

_No response_

View original on GitHub ↗

This issue has 4 comments on GitHub. Read the full discussion on GitHub ↗