Skip to content
Agent Month

How to fix: prompt caching not working / cache_read_input_tokens is zero

Last verified: June 2026· Anthropic and other providers with prompt caching

Where this shows up

Anthropic and other providers with prompt caching

How it shows up

The same root cause surfaces in a few different ways. If any of these match, you're in the right place.

  • Cache read token counts reported as zero on every call despite caching being enabled in the request.
  • A cache that worked in testing and never hits in production, where prompts are assembled dynamically.
  • Hit rates that collapsed after an apparently unrelated prompt edit.
  • Intermittent hits — some sessions cache, others never do — with no obvious difference between them.

Diagnose it first

Confirm which cause you actually have before changing anything — most wasted time here comes from fixing the wrong one.

CheckWhat the result tells you
Print the exact resolved prompt for two consecutive calls and diff them byte for byte.Caching keys on an exact prefix match. Any difference before the cache point — a timestamp, a UUID, a reordered list, a trailing space — invalidates everything after it.
Check whether the stable content is genuinely first in the message array.The prefix must be a prefix. A system prompt placed after a dynamic user message caches nothing, however stable its own content.
Measure the size of the cacheable prefix in tokens.Providers enforce a minimum prefix length below which nothing is cached at all. A prompt that is stable but short may be under the threshold and silently ineligible.
Check the interval between calls against the cache lifetime.Caches expire after a short window on most providers. Low-frequency traffic can miss simply because entries have aged out between requests.

The fix

  1. 1Diff the rendered prompt bytes between two requests to find what differs in the prefix.
  2. 2Move volatile content (timestamps, per-request IDs, the varying question) to the end, after the last cache breakpoint.
  3. 3Serialize JSON deterministically (sorted keys) and keep the tool list stable and ordered.
  4. 4Ensure the cached prefix exceeds the model’s minimum cacheable length — short prefixes silently won’t cache.
  5. 5Verify with cache_read_input_tokens in the usage response once fixed.

Provider-specific behaviour

The error means roughly the same thing everywhere, but each provider signals it differently.

Prefix, not content
Caching matches from the start of the prompt up to a break point, not on similarity. Two prompts that share ninety percent of their content but differ in the first sentence share no cache at all.
Tool definitions count
In tool-using workflows the tool schemas are usually part of the prefix. Generating them in a non-deterministic order — iterating a hash map, for instance — produces a different prefix on every call and is a common invisible cause.

What doesn't work

Common fixes for this error that look right and aren't.

  • Assuming the cache is broken because the first call did not hit.

    The first call writes the entry; only subsequent calls within the lifetime can read it. Measure hit rate over a sequence, not on a single request.

  • Moving dynamic content later but leaving it inside the cached span.

    Everything before the break point must be identical. Dynamic content has to sit after the cache boundary, not merely further down a block that is still being cached.

  • Padding a short prompt to reach the minimum length.

    You pay for the padding on every uncached call and on the write, and the saving rarely covers it. If the stable prefix is genuinely small, caching is not the right lever for that route.

Prevent it

Freeze the system prompt and tool list, inject dynamic context later in the messages, and audit for silent cache invalidators.

Common variations and related errors

You'll usually hit this same root cause under a few different names. Same fix.

  • "prompt caching not working"
  • "cache miss"
  • "no cached tokens"
  • "cache_control not respected"

Frequently asked questions

What causes “prompt caching not working / cache_read_input_tokens is zero”?

Something in the cached prefix changes every request — a timestamp, UUID, unsorted JSON, or a varying tool set — invalidating the cache.

How do I prevent “prompt caching not working / cache_read_input_tokens is zero” from recurring?

Freeze the system prompt and tool list, inject dynamic context later in the messages, and audit for silent cache invalidators.

Why is my cache read count always zero?

Almost always because the prefix is not byte-identical between calls. The usual culprits are a timestamp or request id near the top of the system prompt, tool schemas generated in a non-deterministic order, a retrieved-document list that reorders, or a conversation history appended before the stable block rather than after it. Diff two consecutive resolved prompts byte for byte and the cause is normally visible immediately.

What should go in the cached prefix?

Everything that is identical across calls on that route, in a fixed order, placed first: the system prompt, tool and schema definitions, few-shot examples, and any long reference document the route always includes. Everything that varies — the user's message, retrieved context, conversation history, anything with a time or an identifier in it — goes after the cache break point.

How much does a working cache actually save?

It depends entirely on the ratio of stable prefix to variable content on that route, which is why it pays to measure rather than assume. Routes with a long fixed system prompt and a short user message benefit most; routes where nearly everything varies benefit little. Cached input is billed at a fraction of the standard input rate, so the saving tracks how much of your input is cacheable — and there is a write cost on the first call to account for.