Subagent cache miss on first SendMessage resume (cache_read=0)
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
- Spawn a subagent via
Agent(name: "test", prompt: "...", model: "sonnet") - Agent completes (cache created: ~7k tokens)
- Resume via
SendMessage(to: "<agent-id>", message: "...") - Observe:
cache_read=0, fullcache_create(~14.7k tokens) - Send another
SendMessageto the same agent - 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
This issue has 9 comments on GitHub. Read the full discussion on GitHub ↗