[BUG] Slash command (/usage) during in-flight advisor() call splits assistant message in JSONL, permanently 400s the session (v2.1.154; repro of stale-closed #50527)
Summary
If a local slash command (confirmed here with /usage) fires while an advisor() server-tool call is in flight, Claude Code writes the command's type: system local_command lines into the session JSONL between the server_tool_use entry and its advisor_tool_result entry, even though all the surrounding blocks share the same message.id. On replay the client reconstructs the result as a separate assistant message, orphaning it, and the API rejects every subsequent turn with a 400. The session is permanently unusable from the UI.
API Error: 400 messages.N.content.0: unexpected `tool_use_id` found in `advisor_tool_result` blocks:
srvtoolu_XXX. Each `advisor_tool_result` block must have a corresponding `server_tool_use` block before it.
This is the same bug as #50527, which was triaged (bug, has repro, area:core) and then auto-closed as stale on 2026-05-26 without a fix. The stale-close bot asked for a fresh issue if still relevant. It is: reproduced on v2.1.154 two days later. Likely also the underlying cause of the open report #62885 (same 400 signature, v2.1.152).
Environment
- Version: 2.1.154
- Platform: Windows 11 (win32)
- Trigger command in this instance:
/usage
Repro
- Start a session and prompt something that causes an
advisor()call. - While the
advisor()call is in flight, run a local slash command (e.g./usage,/config,/color). - The assistant turn completes.
- Send any next prompt -> 400. Every subsequent turn fails regardless of input.
JSONL evidence (from an affected session)
All assistant lines below share one message.id (msg_019o7MBeaSNgVWo3DYmXgqRy). The two system lines from /usage are wedged through the middle of that single assistant message:
| line | type | message.id | content block | parentUuid -> |
|---|---|---|---|---|
| L473 | assistant | msg_019o... | text | fc963476 |
| L474 | assistant | msg_019o... | server_tool_use (srvtoolu_...mWUKQiuriP) | fa3d0fa7 |
| L475 | system | (none) | /usage local_command | 9c9e34b2 (= L474) |
| L476 | system | (none) | local_command stdout | e741422a (= L475) |
| L477 | assistant | msg_019o... | advisor_tool_result (srvtoolu_...mWUKQiuriP) | 0f08d0d1 (= L476) |
| L478 | assistant | msg_019o... | thinking | 903fba8a |
Because L477's parentUuid points at a system line (L476) instead of the server_tool_use line (L474), the replay logic treats the advisor_tool_result as a standalone assistant message with no preceding server_tool_use, producing the 400.
A whole-file scan confirmed this was the only interrupted message.id span in the transcript; the three earlier advisor() calls in the same session (where no slash command was run mid-flight) are perfectly contiguous.
Expected behavior
Slash commands invoked during an in-flight tool call should be queued until the assistant turn's content blocks are fully written, or recorded outside the active assistant message. They must never be interleaved within a single assistant turn's block sequence.
Impact
Unrecoverable from the UI. The only fix is hand-editing the session .jsonl: delete the interleaved system lines and re-point the advisor_tool_result line's parentUuid back to the server_tool_use line's uuid (raw-line edit, not a full JSON re-serialize, to preserve byte content). The stuck CC process must be closed first or it clobbers the edit on its next write, then claude --resume <session-id>.
Related
- #50527 (exact root cause; closed as stale, not fixed)
- #62885 (open; same 400 signature, cause not yet identified)
- Distinct from the compaction-orphaning variants (#53365, #55535, #56515, #60523).
This issue has 7 comments on GitHub. Read the full discussion on GitHub ↗