[BUG] new sessions will **never** hit a (full)cache

Status Closed — not planned
Reported on v2.1.113
Maintainer reply None cached
Activity 14 comments · opened Apr 12, 2026 · closed Jul 31, 2026

What's Wrong?

relaunching claude / clearing the session costs 6505 cache-create tokens
even after "just seconds" and super short messages (so this is not about the ongoing 5 minutes vs 1 hour discussion!)

What Should Happen?

assuming no changes where made (looking at you CLAUDE_CODE_DISABLE_GIT_INSTRUCTIONS destroying the system-prompt...)
relaunch/clear should be a 99% cachehit.
but neither skills nor project/CLAUDE.md get cached:

Error Messages/Logs

Traffic-inspection shows

"messages": [
 {
  "role": "user",
  "content": [
   {
    "type": "text",
    "text": "<system-reminder>\nThe following skills are available ...."
   },
   {
    "type": "text",
    "text": "<system-reminder>\nAs you answer the user's questions, you can use the following context:\n# claudeMd\n...."
   },
   {
    "type": "text",
    "text": "alive?",
    "cache_control": {
     "type": "ephemeral"
    }
   }
  ]
 }
],

Steps to Reproduce

Have a statusline show/log you usage.

claude
> alive?
> -> Yes, alive and ready. What do you need? 
# (11k cache read, 6k cache write)
> nice
> -> What are we working on? 
# (18k cache read, 19 cache write)
> /exit
claude
> alive?
> -> Yes, I'm here. What can I help you with?  
# (18k cache read)
> /exit
claude
> are you here?
> -> Yes, I'm here. What can I help you with? 
# (11k cache read, 6k cache write)

-> note that the two string-matched "alive?"´s do hit,
so one can start every claude session with a claude "Hello" and then do the actual work to get the full cache hits ? 🤔
but the "two different questions" gets a 6k token penalty
EDIT: as of 2.1.113 - "cch= started ticking" - ANTHROPIC_BASE_URL-users must set CLAUDE_CODE_ATTRIBUTION_HEADER=0

-> the "initial 11k" is likely some publicly shared tool cache that is hit.

there is no cache marker between system-prompt-part1 (base-prompt + user/CLAUDE.md) and the first user message.
but a whole lot of tokens for skills, and system-prompt-part2 (memory + project/CLAUDE.md)

Claude Model

Sonnet (default)

Is this a regression?

I don't know

Last Working Version

_No response_

Claude Code Version

2.1.104

Platform

Anthropic API

Operating System

Ubuntu/Debian Linux

Terminal/Shell

Xterm

Additional Information

also came across the discussion here https://news.ycombinator.com/item?id=47740381
"keeping your context small" (and clearing often) is(used to?) be the way to go - but without cachepoint the reverse would be true? -> more compute for you, less expensive for users - what sounds wrong...

Note that this is especially NOT about the 5-minute vs 1 hour discussion,
the claude launches above where all within 15 seconds ;)

View original on GitHub ↗

12 Comments

github-actions[bot] · 4 months ago

Found 3 possible duplicate issues:

  1. https://github.com/anthropics/claude-code/issues/44045
  2. https://github.com/anthropics/claude-code/issues/43657
  3. https://github.com/anthropics/claude-code/issues/44869

This issue will be automatically closed as a duplicate in 3 days.

  • If your issue is a duplicate, please close it and 👍 the existing issue instead
  • To prevent auto-closure, add a comment or 👎 this comment

🤖 Generated with Claude Code

wadabum · 4 months ago

not a dupe, resume is not involved here.
also fix is practically included: "move that cache_control one message up."

abraxasresearch · 4 months ago

Confirming same issue on macOS M1, Claude Max, Sonnet 4.6, v2.1.104. Fresh sessions hitting 23%+ context used after 2-3 exchanges. Was not happening before today's auto-update.

cnighswonger · 4 months ago

This is a distinct mechanism from the 5m/1h TTL discussion and worth tracking separately — nice catch.

Your traffic inspection shows the key structural issue: skills and project/CLAUDE.md content land in messages[0] user-content blocks, not in the system[] prefix. Anthropic's prompt caching is prefix-based — it matches from the beginning of the request forward. Content in messages[0] sits AFTER the system prompt and tool definitions, so any change to it (or even reordering within it) invalidates the cache for everything that follows, even if the system prompt and tools are byte-identical.

We've been measuring this from a different angle with our claude-code-cache-fix interceptor. Our CACHE_FIX_DEBUG=1 mode logs per-call prompt-size breakdowns:

PROMPT SIZE: system=27539 tools=76152 injected=1626 (skills=1626 mcp=0 deferred=0 hooks=0)

The injected=1626 is the skills block you're seeing — it's in messages[0] and contributes to per-session cache instability. On a fresh session / /clear, the skills block content is regenerated and may differ from the prior session's version even if your actual skills haven't changed (ordering, whitespace, deferred-tool registration timing).

Your #47107 finding about git status in the system prompt is the other half of this — the system prompt itself changes on every file edit because includeGitInstructions (default: true) injects live git status output. So you have cache busting from BOTH ends: system prompt changes from git status at the front, and skills/CLAUDE.md changes from messages[0] regeneration at the back.

Our interceptor addresses part of this — we sort and stabilize the skills, deferred-tools, and MCP blocks within messages[0] to reduce ordering jitter. But we don't currently address the git status system-prompt instability from #47107. That's a good lead for a future fix.

For anyone wanting to measure this on their own sessions: npm install -g claude-code-cache-fix@1.7.1 with CACHE_FIX_DEBUG=1 will log the per-section sizes and prefix diffs that make these cache busts visible.

ZWhiteTrace · 4 months ago

Datapoint across 159 local sessions (v2.1.71 – 2.1.104):

First-turn cache_read == 0 rate by version:

| version | sessions | zero_read_rate |
|---|---|---|
| 2.1.94 | 11 | 90.9% |
| 2.1.97 | 10 | 50.0% |
| 2.1.100 | 32 | 40.6% |
| 2.1.101 | 35 | 40.0% |
| 2.1.104 | 7 | 28.6% |

Trend is improving on newer versions, though 40% zero-hit on 2.1.100+ is still a meaningful amount.

Caveat: uncontrolled sampling (skills and CLAUDE.md content vary across sessions), so weaker than the controlled "no changes made" repro in the OP. Sharing as a rough corroboration that first-turn cache misses are common enough to be worth investigating, even if not strictly "never."

ZWhiteTrace · 4 months ago

For anyone wanting to measure this on their own sessions, I published the analysis script:
https://gist.github.com/ZWhiteTrace/7f23ee2920ba6e1dd8eacd79478e90ae

It reports first-turn cache_read by version out of the box, so reproducing the table above (or finding different trends) is just running one command.

junaidtitan · 4 months ago

Cache misses on relaunch are expensive. We open-sourced Cozempic which prunes session bloat so the context payload is smaller and more cache-friendly between sessions. Less content changing between turns = higher cache hit rates.

The guard daemon runs automatically and keeps sessions lean with 18 lossless pruning strategies.

\pip install cozempic && cozempic init\

Would be curious if you see cache hit rates improve — \cozempic diagnose\ shows your current cache read vs creation ratio.

wadabum · 4 months ago

FYI if you are an ANTHROPIC_BASE_URL user:

This will not entirely make this problem here go away,
-- but should get you from cache hitting only on the tools,
-- to hit tools and system-prompt (+~/.claude/claude.md).

-> skills and system-messages (+projects-claude.md) will still miss if not using the claude "Hello" thing,
EDIT: as of 2.1.113 - "cch= started ticking" - BASE_URL-users must set CLAUDE_CODE_ATTRIBUTION_HEADER=0
so this here is is still its own issue that needs an extra cache_control in the code to get fixed...
(or one of the claude-code-cache-fix-interceptors ran userside)

---

Still getting inflated numbers? check:

  • changed any files? (even new files count!)

https://github.com/anthropics/claude-code/issues/47107

  • and try restarting rather than /clear ing 😢

https://github.com/anthropics/claude-code/issues/47756

cnighswonger · 4 months ago

Good breakdown of the cache layers. To confirm what the interceptor covers in that stack:

  • toolstool_sort pins deterministic order, tool_use_input_normalize canonicalizes field order
  • system-prompt + CLAUDE.mdfingerprint_strip removes the attribution hash (same effect as CLAUDE_CODE_ATTRIBUTION_HEADER=0 but automatic)
  • skills + system-messages + project CLAUDE.mdrelocate pins these to messages[0] in stable order, reminder_strip drops volatile bookkeeping reminders, smoosh_split / smoosh_normalize handle the content-folding drift

So layers 1-3 are all addressed, plus several per-turn drift classes (cache_control_normalize, cache_control_sticky, session_start_normalize, continue_trailer_strip).

The attribution header issue (#50085) is worth fixing upstream regardless — users on ANTHROPIC_BASE_URL without the interceptor are getting silently burned.

cnighswonger · 3 months ago

Confirming this is still observable in 2.1.131. New sessions show the same pattern @wadabum described — skills and project CLAUDE.md remain cache-miss territory across relaunches, even seconds apart on identical context.

The interceptor work in cache-fix closes some of the surface (tools order, system-prompt, top-level CLAUDE.md via fingerprint strip) but not the skill / project-CLAUDE.md path @wadabum specifically called out — those still need an upstream fix at the prefix construction step. This contributes meaningfully to the per-turn cache_read figures several of us have been measuring on heavy sessions.

Worth keeping open as a reference for ongoing community work.

— AI Team Lead

wadabum · 3 months ago

still relevant in >=2.1.150

graehl · 2 months ago

Besides the theory that cache is simply not checked, I'm informed that the system prompt (or just after it) inserts a git hash (if this sort of 'the current time is ...' 'git HEAD is ...' dynamic content is to be inserted, clearly it OUGHT to occur after all the project instructions reads to allow for a longer prefix hit). you can also see that /clear does far less than it could/should (i.e. fork from just before the session-opening turn if project boot files were unchanged)

Showing cached comments. Read the full discussion on GitHub ↗