400 role 'system' is not supported — client builds malformed request after large, twice-compacted session (unrecoverable in-place)
Environment
- Claude Code: 2.1.139
- Platform: Linux 6.8.0, CLI entrypoint
- Model:
claude-opus-4-7, 1M context (endpoint/v1/messages?beta=true)
Summary
After a long-running session that twice exceeded ~1M input tokens and was compacted twice, every subsequent turn fails with:
API Error: 400 role 'system' is not supported on this model
The failure is deterministic — identical on every retry. The persisted session transcript (JSONL) contains no role:"system" message anywhere; the malformed system-role entry is introduced at request-construction time, not present in stored history.
The session is therefore permanently unusable in-place: /compact cannot recover it, because compaction also issues an API call built the same way.
Evidence (from the session transcript)
- 5,355 transcript events; valid JSONL, 0 parse errors.
- Two
compact_boundaryevents: - manual trigger —
preTokens: 1001871→postTokens: 11727 - auto trigger —
preTokens: 974919→postTokens: 11880 - An earlier, separate
400 invalid_request "Prompt is too long"preceded the first (manual) compaction. - The last successful turn completed normally on
claude-opus-4-7. The very next user message — plain text, no attachments — produced the400 role 'system'error. - 5 consecutive attempts (1 original + 4 retries) all failed identically.
- Grep of the full transcript for
"role":"system"/"role": "system": 0 hits. - Each failed attempt appends a synthetic assistant error message (
model: "<synthetic>",isApiErrorMessage: true) to history.
Expected behavior
The client should never place a system-role message in the messages array — system content belongs in the top-level system request parameter. Outgoing messages should be validated to role ∈ {user, assistant} before send.
Impact
A session in this state is unrecoverable in-place. /compact fails for the same reason. The only escape is /clear (total context loss) or abandoning the session — a hard data-loss cliff for long, heavily-compacted sessions.
Suspected area
The injected system-role message is generated at request-build time, likely in the context-management / post-compaction summary reconstruction path (this session had been compacted twice from ~1M tokens). Worth checking how the post-compaction summary is mapped into the messages array.
---
The full session transcript (~17 MB, contains internal project context) is available privately on request.
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗