[BUG] Background agents fail with cache_control TTL ordering error (1h after 5m)
Preflight Checklist
- [x] I have searched existing issues and this hasn't been reported yet
- [x] This is a single bug report (please file separate reports for different bugs)
- [x] I am using the latest version of Claude Code
What's Wrong?
When running multiple background agents (run_in_background: true) in a long session with many MCP servers configured (~12 servers, ~100+ tools), some agents fail with a 400 API error indicating that cache_control TTL blocks are in the wrong order:
API Error: 400 {"type":"error","error":{"type":"invalid_request_error",
"message":"messages.60.content.6.cache_control.ttl: a ttl='1h' cache_control
block must not come after a ttl='5m' cache_control block. Note that blocks are
processed in the following order: `tools`, `system`, `messages`."}}
The agents that fail report "Not logged in · Please run /login" as their result, which is misleading — the actual cause is the 400 API error, not an authentication issue.
Reproduction Pattern
The error is intermittent and concurrent-dependent:
- Running 7 background agents simultaneously: ~3 out of 7 fail
- Running 3 background agents: more reliable but still occasional failures
- Sequential agents: no failures observed
- The error appears more likely in long sessions (many prior messages/tool calls)
Failed agents consistently show very low token counts (596-780 tokens) despite having 50-94 tool uses logged, suggesting they ran for a while using cached context before hitting the TTL ordering error on a subsequent API call.
Root Cause Hypothesis
Claude Code uses both ttl='5m' and ttl='1h' cache_control blocks across tools, system prompts, and messages. The API requires that all 1h blocks come before any 5m blocks (ordered by descending TTL). When multiple background agents run concurrently in a session with many MCP server tools, the cache_control block ordering becomes inconsistent — likely because the tool/system/message blocks are assembled in a non-deterministic order across concurrent agent API requests.
What Should Happen
Cache_control blocks should always be ordered with longer TTLs first (1h before 5m), regardless of how many concurrent agents are running or how many MCP tools are loaded.
Error Messages/Logs
API Error: 400 {"type":"error","error":{"type":"invalid_request_error",
"message":"messages.60.content.6.cache_control.ttl: a ttl='1h' cache_control
block must not come after a ttl='5m' cache_control block. Note that blocks are
processed in the following order: `tools`, `system`, `messages`."},
"request_id":"req_011CZGhwSmoye2tigfwqcY9d"}
Agent result when this error occurs:
Not logged in · Please run /login
Steps to Reproduce
- Configure 10+ MCP servers (GitHub, Playwright, context7, pencil, shadcn, mobile-mcp, etc.)
- Start a long session with many tool calls (build up conversation history)
- Dispatch 5+ background agents simultaneously using the Agent tool with
run_in_background: true - Some agents will fail with the TTL ordering error
- The failed agents report "Not logged in" instead of the actual API error
Workarounds
- Run fewer concurrent agents (3 instead of 7)
- Temporarily disable unused MCP servers to reduce tool count
- Start a fresh session to reset conversation length
- Run agents sequentially instead of in parallel
Claude Model
Opus
Is this a regression?
I don't know
Last Working Version
_No response_
Claude Code Version
2.1.81 (Claude Code)
Platform
Anthropic API
Operating System
macOS
Terminal/Shell
zsh
Additional Information
Related issues (different cache_control bugs, same area):
- #23220 —
cache_control.ephemeral.scopeerror - #30920 / #30989 —
defer_loading+cache_controlconflict - #8419 / #8901 — maximum cache_control blocks exceeded
- #36243 — 1h TTL not applied to subagents
MCP servers active during reproduction: context7, pencil, github, playwright, mobile-mcp, shadcn, refero, magic, lottiefiles, iconify, Gmail, Google Calendar
Additional observation: The misleading "Not logged in" error message when the actual cause is a 400 API error makes debugging much harder. The error handling should surface the real API error to the user/agent.
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗