Subagent cache miss on first SendMessage resume (cache_read=0)

Resolved 💬 9 comments Opened Apr 7, 2026 by labzink Closed May 24, 2026

Description

When resuming a subagent via SendMessage, the first resume call always results in a full cache miss (cache_read=0), even though the previous Agent call created a cache just seconds earlier. Subsequent SendMessage calls to the same agent correctly hit the cache.

Root Cause Found

Confirmed via mitmproxy captures comparing raw /v1/messages request bodies.

system[1] — the only cached block that differs — contains a different identity string between Agent() and SendMessage():

| Call | system[1] text | cache_control |
|---|---|---|
| Agent() | "You are Claude Code, Anthropic's official CLI for Claude." | ephemeral |
| SendMessage() | "You are a Claude agent, built on Anthropic's Claude Agent SDK." | ephemeral |

system[2] (3,285 chars — actual instructions) is byte-for-byte identical. system[0] (billing header) also changes but has no cache_control and does not affect caching.

The identity string swap in system[1] busts the entire cache prefix, producing cache_read=0 with no partial hit. The fix is in the CLI orchestrator: when resuming a subagent via SendMessage(), preserve the same identity string used in the original Agent() call.

Reproduction

  1. Spawn a subagent via Agent(name: "test", prompt: "...", model: "sonnet")
  2. Agent completes (cache created: ~7k tokens)
  3. Resume via SendMessage(to: "<agent-id>", message: "...")
  4. Observe: cache_read=0, full cache_create (~14.7k tokens)
  5. Send another SendMessage to the same agent
  6. Observe: cache_read=14.7k — cache hit works

Observed behavior

| Call | cache_create | cache_read | Notes |
|------|-------------|------------|-------|
| Agent (1st call) | 7,084 | 7,504 | Partial hit from shared system prompt |
| SendMessage (2nd call) | 14,675 | 0 | Full cache miss |
| SendMessage (3rd call) | 83 | 14,675 | Cache hit |

Time between calls #1 and #2: ~85 seconds (well within 5-min cache TTL).

Expected behavior

The second call (first SendMessage) should reuse the cache created by the first call. The prompt prefix (system prompt + initial user message + assistant response) should remain stable across resume, preserving cache alignment.

Impact

For large contexts (~50k tokens) on Opus, each unnecessary cache miss costs ~10x more than a cache hit ($0.75 vs $0.075). This makes the SendMessage resume pattern significantly more expensive than spawning a fresh Agent with summarized context — which defeats the purpose of resume.

Environment

  • Claude Code CLI (latest)
  • Model: claude-sonnet-4-6 (subagent), claude-opus-4-6 (orchestrator)
  • OS: macOS 13.5

View original on GitHub ↗

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