anthropics / anthropics/claude-code

[BUG] Regression in 2.1.266: client emits system message at an invalid position → API 400 "role 'system' must precede an 'assistant' message or end the array"

Ouverte
#94,294 1 commentaire 0 réactions 0 personnes assignées Voir sur GitHub
area:core bug platform:macos regression
Langage dominant
Python
Étoiles
145k
Forks
23.1k
Métriques de merge des PR
Métriques de PR en attente

Description

### Preflight Checklist

- [x] I have searched [existing issues](https://github.com/anthropics/claude-code/issues?q=is%3Aissue%20state%3Aopen%20label%3Abug) 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?

Since v2.1.266, Claude Code intermittently builds a request whose `messages` array contains a `system`-role entry in a position the Messages API rejects. The turn fails with:

API Error: 400 messages.N: role 'system' must precede an 'assistant' message or end the array; the directive-only form (content: [] with output_config) is accepted at any position

N varies (7, 13, 16, 19, 138, 151). There is no way to avoid or recover from it other than retrying the turn.

This is a clean regression. I scanned every session transcript in ~/.claude/projects/**/*.jsonl and correlated the error against the `version` field on each entry:

- 28 distinct versions used before the regression, from 2.1.142 (2026-05-26) through 2.1.260 (2026-09-11): zero occurrences
- First occurrence: 2026-09-11 09:24:56 on 2.1.266 — the first day 2.1.266 appears in my logs
- Still occurring on 2.1.268 and 2.1.270 (2026-09-14)

Impact so far: ~48 failed turns across 14 sessions in 3 separate projects.

Possible lead: a large share of failures are preceded within a few transcript entries by client-generated system-subtype records — most often `system/stop_hook_summary`, also `system/turn_duration` and `system/away_summary`. Notably `stop_hook_summary` entries appear even though I have no hooks configured. That suggests these internal system records may be serialized into the outgoing messages array without the position check the API enforces. I can't confirm that from transcripts alone — it's a lead, not a diagnosis. Also common nearby: `queue-operation` (queued user messages) and `attachment` / `file-history-snapshot` records, so an interrupted or queued turn may be part of the trigger.

No deterministic repro — it appears mid-session during ordinary use across unrelated projects, roughly once every few dozen turns, not tied to any one project, skill, or tool. Retrying usually succeeds.

### What Should Happen?

The client should never place a `system`-role entry in a position the Messages API rejects — or should use the directive-only form (content: [] with output_config), which is valid at any position. The turn should complete normally instead of 400ing and being lost.

### Error Messages/Logs

```shell
API Error: 400 messages.7: role 'system' must precede an 'assistant' message or end the array; the directive-only form (content: [] with output_config) is accepted at any position

Observed occurrences (timestamp, version):
2026-09-11T09:24:56 2.1.266 <-- first
2026-09-11T09:25:51 2.1.266
2026-09-11T09:26:39 2.1.266
2026-09-11T09:27:07 2.1.266
2026-09-11T09:28:59 2.1.266
2026-09-11T09:34:51 2.1.266
2026-09-11T09:55:08 2.1.266
2026-09-11T12:31:52 2.1.266
2026-09-11T12:32:23 2.1.266
2026-09-11T12:39:19 2.1.266
2026-09-11T13:50:36 2.1.266
2026-09-11T14:10:46 2.1.266
2026-09-11T14:22:07 2.1.268
2026-09-11T14:23:28 2.1.266
2026-09-11T14:41:14 2.1.266
2026-09-14T08:09:19 2.1.266
2026-09-14T08:36:02 2.1.266
2026-09-14T08:54:23 2.1.266
2026-09-14T12:35:14 2.1.270
2026-09-14T13:30:31 2.1.266
2026-09-14T13:30:50 2.1.270
2026-09-14T13:35:07 2.1.266
2026-09-14T13:37:19 2.1.266
2026-09-14T13:37:28 2.1.266
2026-09-14T13:39:56 2.1.266
2026-09-14T13:40:21 2.1.266
```

### Steps to Reproduce

No deterministic repro — the failure appears mid-session during ordinary use, roughly once every few dozen turns, across unrelated projects, and is not tied to any one project, skill, or tool. Retrying the turn usually succeeds. What I can give you is an exact way to observe it and confirm the version boundary from any affected machine's own transcripts.

To observe:
1. Install 2.1.266 or later (reproduced on 2.1.266, 2.1.268, 2.1.270).
2. Use Claude Code in the desktop app normally — multi-turn sessions with tool use, queued messages, and interruptions. No special configuration; I have no hooks configured (settings.json contains only permissions, theme, skipWorkflowUsageWarning).
3. Within a few dozen turns a turn fails with:
API Error: 400 messages.N: role 'system' must precede an 'assistant' message or end the array; the directive-only form (content: [] with output_config) is accepted at any position

To confirm the version boundary from transcripts (this is how I established it):

cd ~/.claude/projects && find . -name '*.jsonl' -print0 | xargs -0 grep -h "must precede an" \
| python3 -c "
import sys,json
for l in sys.stdin:
try: d=json.loads(l)
except: continue
print(d.get('timestamp','?')[:19], d.get('version','?'))
" | sort

On my machine this returns zero rows for all 28 versions from 2.1.142 (2026-05-26) through 2.1.260, and the first row is 2026-09-11T09:24:56 on 2.1.266 — the first day 2.1.266 appears in my logs.

Scope check — the failures are on main-thread interactive turns, not subagents. Every affected transcript entry has userType "external" and isSidechain false; zero sidechain occurrences across 14 sessions in 3 projects.

I can't produce a minimal code example because no file or code triggers it — the malformed request is built by the client, and nothing in the user's project is involved. If it helps, I can supply the raw transcript entries around a failure, though I'd need to redact work content first.

### Claude Model

Opus

### Is this a regression?

Yes, this worked in a previous version

### Last Working Version

_No response_

### Claude Code Version

2.1.270

### Platform

Anthropic API

### Operating System

macOS

### Terminal/Shell

Terminal.app (macOS)

### Additional Information

Version reporting caveat: `claude --version` returns 2.1.270, but the desktop app pins a bundled CLI per session. My current session runs 2.1.266 (CLAUDE_CODE_EXECPATH=.../Claude/claude-code/2.1.266/claude.app/..., AI_AGENT=claude-code_2-1-266_agent), which is why failures dated 2026-09-14 still log version 2.1.266 alongside ones logging 2.1.270. Updating the CLI may not move existing sessions off the affected build.

Scope: ~48 failed turns across 14 sessions in 3 projects since 2026-09-11. All on main-thread interactive turns — every affected entry has userType "external" and isSidechain false, zero sidechain occurrences.

No hooks configured. settings.json contains only permissions, theme, skipWorkflowUsageWarning.

One lead, unconfirmed: many failures are preceded within a few transcript entries by client-generated system-subtype records — most often system/stop_hook_summary, also system/turn_duration and system/away_summary. stop_hook_summary appears despite no hooks being configured. Possibly these internal system records are serialized into the outgoing messages array without the position check the API enforces. Also frequently nearby: queue-operation (queued user messages) and attachment / file-history-snapshot records.

Guide de contribution

Aucun guide de contribution indexé pour ce dépôt

Évaluation

Cette issue n'a pas encore été évaluée.

Recevez les nouvelles issues par e-mail

Un résumé court des issues GitHub adaptées aux débutants.