Context compressor non-atomically splits server_tool_use/advisor_tool_result pairs, crashing session with 400

Status Closed — duplicate
Maintainer reply None cached
Activity 2 comments · opened Jul 25, 2026 · closed Aug 15, 2026

Summary

When context compression fires ('Crunched for Xs'), the compressor can drop a server_tool_use block while keeping its paired advisor_tool_result in a subsequent message. The next API call then fails with a 400 that cannot be retried, killing the session.

Error

messages.5.content.0: unexpected `tool_use_id` found in `advisor_tool_result` blocks: srvtoolu_0113SF3GSdjhpbcUPzkeVk5L. Each `advisor_tool_result` block must have a corresponding `server_tool_use` block before it.

Steps to reproduce

  1. In a long session, call the advisor tool (or any path that emits a server_tool_use block).
  2. Continue working until context pressure triggers compression.
  3. If the compression boundary falls between the assistant message containing the server_tool_use and the user message containing the advisor_tool_result, the tool-use block is dropped but the result block survives.
  4. The next turn sends an invalid history → 400 → session dead.

What I observed

  • Claude Code tried model fallback: Opus 5 (1M) → Opus 5 → Sonnet 4.6. All three hit the same 400 because the history itself is corrupt, not the model.
  • Triggering input was "continue executing plan" — an innocuous prompt that happened to be the first turn after compression.

Expected behavior

The compressor should treat server_tool_use + its corresponding advisor_tool_result as an atomic pair: either keep both or drop both (replacing both with a summary entry if needed).

Environment

  • Claude Code version: (from session — exact version not captured)
  • Branch: jukim07/feat/clinician-playwright-fixtures
  • Model at time of crash: Opus 5 (1M context)

View original on GitHub ↗

This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗