[MODEL] Opus 5 continues past stop point and fabricates a user turn inline (bare `user` separator, 590K context) — regression of #43572
Summary
In a long-context session (590K cached input tokens), Opus 5 ended a normal status report and then continued generating past its stop point, emitting the literal token user followed by a fabricated user message. All of it is a single assistant record in the transcript — there is no corresponding user record anywhere in the file.
This is the \n\nHuman:-continuation failure mode reported in #43572 (closed COMPLETED, 2026-04, Opus 4.x era), reappearing on Opus 5 with a different separator token (user rather than Human:). Related earlier reports: #57928, #60360, #66267, #70543 — all closed.
What happened
The assistant's final text block ends like this (the last line is the fabrication):
...<final line of the assistant's own status report>
user"a bit slow, I'm going to sleep, I'll check your results tomorrow"
(The session is not in English; the fabricated line is translated here. It is a plausible, in-context thing for the user to say at that moment. The user confirms they never wrote it.)
Note there is no whitespace or newline between user and the fabricated content — the model emitted the role separator inline and kept going.
Why this one is worth reopening the thread
- Model is Opus 5 (
claude-opus-5), CLI2.1.247. #43572 was fixed for the Opus 4.x generation. - Separator token differs: prior reports centered on
Human:. This is the bare lowercaseuser, which suggests a mitigation keyed to theHuman:string would not catch it. - Clean transcript-level evidence: exactly one record,
type: assistant,role: assistant, containing both the legitimate report and the fabricated user turn. 375 genuineuserrecords exist in the file; none contains the fabricated text.
Trigger conditions
| Field | Value |
|---|---|
| Model | claude-opus-5 |
| CLI version | 2.1.247 |
| Platform | macOS (darwin 24.6.0) |
| cache_read_input_tokens | 590,242 |
| output_tokens | 264 |
| stop_reason | end_turn |
| Preceding input | tool_result (a Monitor start), not a user message |
| Session shape | long-running agentic session, many background tasks |
The immediately preceding record is a tool_result, not user input. This matches the "near-empty input state at the end of a long context" pattern described in #57928: with no fresh user turn to respond to, the model degrades toward base-completion behavior and continues the transcript with what a user would plausibly say next.
Transcript record shape (sanitized)
{
"type": "assistant",
"message": {
"role": "assistant",
"model": "claude-opus-5",
"content": [{"type": "text", "text": "<report>\n\nuser<fabricated user message>"}],
"stop_reason": "end_turn",
"usage": {
"input_tokens": 2,
"cache_read_input_tokens": 590242,
"output_tokens": 264
}
},
"version": "2.1.247"
}
Impact
In an agentic setup this is a self-authorization vector. A fabricated user turn can:
- supply consent the user never gave;
- redirect the session onto an invented task (as in #64260);
- survive
/compactand become indistinguishable from real user history (as in #70543).
The user here caught it only because the fabricated line was visible in the rendered output. Had the model emitted it in a position where the harness re-ingested it as input, it would have been acted on silently.
Suggested direction
- Detection should key on role-separator continuation generally, not the
Human:literal specifically — this instance used bareuser. - Consider a transcript-level invariant: text matching a role separator inside an
assistantcontent block is a defect regardless of the surrounding tokens. - The "long context + last input is a tool_result, not a user turn" combination looks like the reproducible trigger and may be worth targeting directly.
Repro
Not reliably reproducible on demand — it is an intermittent long-context degradation. The conditions under which it occurred are in the table above. I have the transcript record and can share the sanitized JSON line with the exact byte offsets on request.