[BUG] Loading a tool for the first time mid-session (e.g. skill, MCP, tool-search) invalidates cache
Preflight Checklist
- [x] I have searched existing issues and this hasn't been reported yet (closest are #42309, #44045, #41930, but those are about
--resume/billing-sentinel, not mid-session tool loading) - [x] This is a single bug report
- [x] I am using the latest version of Claude Code
What's Wrong?
Every first-time tool load in a session = a full cache miss on the next turn.
The tools array is the first block in the request so it's right at the front of the cache prefix, which means the second it grows everything after it is invalid. I know tools load lazily, I just figured a new one gets tacked onto the end, not nuke the cache for the whole conversation.
Caught it with an MITM proxy on /v1/messages:
| Turn | Trigger | tools size | cache_read | cache_creation |
|---|---|---|---|---|
| ~37 | first TodoWrite use | 13 → 14 | 84,858 -> 0 | 120,845 |
| ~57 | invoked an MCP-backed skill (loaded 3 MCP tools) | 14 → 17 | 128,716 -> 0 | 150,796 |
That second row is ~150k tokens re-encoded in one turn, around $3 at Fable's cache-write rate.
What Should Happen?
Adding a tool mid-session shouldn't re-encode the whole conversation. Easiest fix is probably to just declare the deferred tools at session start so the array never grows. If that's not doable, warn the user before it invalidates the cache, the way the CLI already does when you resume a conversation past its TTL.
Error Messages/Logs
N/A
Steps to Reproduce
- Use a config where tools load lazily (default in recent versions: deferred tool-search on, an MCP server or a skill installed).
- Start a session and work until the conversation is large (e.g. ~100k+ tokens).
- Trigger a first-time tool load this session, e.g. invoke a skill that pulls in MCP tools, or use an MCP / deferred tool you haven't used yet this session.
- Inspect that single turn's API usage.
cache_read_input_tokenswill collapse to 0 whilecache_creation_input_tokenswill balloon to your conversation size for that turn.
Claude Model
The bug is model-independent
Is this a regression?
I don't know, this appears to be inherent to lazy tool loading, not a recent change.
Last Working Version
N/A
Claude Code Version
2.1.197, VS Code Extension
Platform
Anthropic API
Operating System
macOS
Terminal/Shell
VS Code Extension
Additional Information
This is on Claude Code, not the API. It's growing the tools array lazily mid-session instead of declaring everything up front.
Not the same as the --resume stuff in #42309 / #44045 either, mine is one continuous session, no resume. #42309 says the deferred-tools/MCP/skill caching behavior is undocumented, so here's a real number for it.
4 Comments
@oakif One way to make these issues easier to debug is to capture a complete execution trace of the session - tool registrations, MCP initialization, cache state changes, context mutations, and model/tool transitions. That makes it much easier to pinpoint exactly where the cache became invalid instead of debugging from logs alone.
@mayank609 Thanks, that's actually how I caught this. I ran a small MITM forward proxy in front of
api.anthropic.comrouted throughHTTPS_PROXYinstead ofANTHROPIC_BASE_URL. It dumps every request body along with the response's usage numbers to a log. That way I can byte diff two subsequent requests to see what differed.That's also how I got the trace behind the numbers in my original post. I can write up the setup if it'd help, it's a pretty small script.
I'd like to comment on another cache miss that I experienced. This one is clearer than the previous one. The session itself is was 13 lines long when this happened. One ToolSearch call in and the cache was invalidated; this was even without a usable tool in the search result.
Please have a look at the screenshot below at the mid-session cache invalidation.
<img width="414" height="597" alt="Image" src="https://github.com/user-attachments/assets/7e1345f5-574b-4cf4-9f53-29898e74326c" />
I asked how to add an email to a TestFlight tester list.
ToolSearchran on the string "testflight tester add beta" and matched 10 unrelated tools. The final answer from Sonnet ended up being "there's no tool for this, go use App Store Connect directly" but still was associated with a cache invalidation.It looks like
ToolSearchcan (un)reliably break prompt caching, despire the claims about ToolSearch on the website.Confirming instance, captured while isolating a different cache bug (#86299):
Two adjacent turns of the same live session (bare
claude-agent-sdkclient,setting_sources=[], no skills involved): thetoolsarray (97,767 bytes serialized) diverges at offset 72,055 —WaitForMcpServersappears in turn 2 that wasn't in turn 1.cache_readdrops to 0, full prefix re-written.So this isn't only skill/MCP lazy-loading on first use — internal tools also join the array between turns with no user action at all. Same failure applies across process restarts: if the deferred-tools state differs at resume, the whole session cache is dead from the
toolsblock (this masked #86299 in our first measurements).Captured request bodies available via a logging proxy on
ANTHROPIC_BASE_URL— happy to attach diffs if useful.