Headless + interleaved thinking + tool use: thinking block intermittently mutated → 400 "thinking blocks in the latest assistant message cannot be modified"
Summary
When running headless (claude -p with stream-json I/O) using claude-opus-4-7 with extended (interleaved) thinking on, multi-tool turns intermittently fail with:
API Error: 400 messages.1.content.21: `thinking` or `redacted_thinking` blocks in the latest assistant message cannot be modified. These blocks must remain as they were in the original response.
The content.{13,17,21,...} index varies with turn length. It is intermittent — the same prompt usually succeeds on a fresh run — and reproduces on both 2.1.148 and 2.1.154 (upgrading did not fix it).
Environment
- Claude Code 2.1.148 and 2.1.154 (both affected)
- Invocation:
claude -p --output-format stream-json --input-format stream-json --verbose --strict-mcp-config --permission-mode bypassPermissions - Model:
claude-opus-4-7, default (extended/interleaved) thinking enabled - Direct Anthropic API — no proxy, no custom
ANTHROPIC_BASE_URL - Linux, Node 22
What happens
On a turn that interleaves thinking with several tool calls — i.e. the assistant message is [thinking, tool_use, thinking, tool_use, …] (deep content index = many such blocks) — Claude Code executes the tools and resends the assistant turn alongside the next tool_result. The API then rejects it: a thinking block in that assistant message no longer matches the bytes originally returned, so it is treated as "modified."
Because this is headless -p mode, Claude Code drives the agent loop and builds the messages array internally (the wrapper only feeds the initial user message and reads the stream). So the mutation happens inside Claude Code, not in caller-supplied messages.
Repro (intermittent, not fully deterministic)
- Run
claude -pheadless as above: opus, extended thinking,bypassPermissions. - Give it a task that triggers ~8–15 Bash tool calls (e.g. "gather signals from these sources, then summarize").
- A fraction of runs fail with the 400 above; re-running the same prompt from a fresh session usually succeeds.
Expected
Claude Code should preserve thinking / redacted_thinking blocks (including their signature) byte-for-byte when replaying the assistant turn with tool results, so the turn round-trips without the 400.
Impact
Intermittent hard failures of automated / headless agent runs that use extended thinking together with tools. The error text ("blocks ... cannot be modified") is also misleading for operators, since the caller never modified anything.
Happy to provide more details or a sanitized stream-json transcript if useful.
This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗