← All posts
Mechanics5 min read

Cache minimums, or why nothing below 1,024 tokens ever caches

Every model has a published minimum cacheable prefix, the API silently ignores breakpoints below it, and the minimums are not monotonic across generations. Look yours up.

There is a floor under prompt caching, and the API will not tell you when you are below it.

Every Claude model has a published minimum cacheable prefix length. Mark a cache_control breakpoint on a span shorter than the minimum and the request succeeds, the response arrives, nothing warns — and nothing caches. You pay normal input rates, forever, on a prompt your code confidently believes is cached. The failure is perfectly silent, which is what makes it worth a post: every other cache failure at least shows up as writes in your usage object. This one shows up as nothing at all.

The minimums are not what you would guess

The current published values run from 512 to 4,096 tokens depending on the model, and the detail that breaks everyone's intuition is that they are not monotonic across generations. Opus 4.6's minimum is 4,096; the newer Opus 5 is 512. Sonnet 4.6 and Sonnet 5 sit at 1,024. Haiku 4.5 is 4,096 while the older claude-3-5-haiku is 2,048. Newer is not lower, bigger is not higher, and there is no rule that predicts a model's minimum from its tier or its age. You look each one up, or you get it wrong.

We got it wrong twice, in opposite directions, and the second direction is the instructive one. Our first table was too low — it judged a 1,500-token Opus prefix cacheable when the real minimum was 4,096, and forecast savings on a span the API was silently ignoring. The correction raised everything to the highest value anyone could remember, on the reasoning that erring high is the safe direction. It is not. It is a different wrong direction: the table then sat 2–8x too high on five current models, and one agent measuring 1,415 stable tokens was told "your prompt is too small to cache" against a stored minimum of 2,048 — on Sonnet 4.6, whose real minimum is 1,024. Eligible the whole time, written off, and invisible: a too-small verdict looks exactly like a correct one from the outside. "Fail closed" needs a direction argued per case. For a model you can look up, the only right answer is the published one; the 4,096 fail-closed default is reserved for models we genuinely cannot identify.

The estimation trap: your 1,050 tokens may be 980

The second half of the problem is that you rarely know your prefix length exactly. Without running a tokenizer, everyone — including us — estimates with the standard chars/4 heuristic. Real English prose runs closer to 4.14 characters per token on the workloads we have measured, which means chars/4 systematically overestimates the token count by a few percent.

Usually that error is harmless. At the floor it is decisive: a prompt that chars/4 calls 1,050 tokens is around 980 real tokens — under a 1,024 minimum. Your arithmetic says cached; the API silently disagrees, and there is no error channel through which it will ever say so. If your estimated prefix sits within about 10% of the model's minimum, treat its cache status as unknown until you have verified it from the usage object: a cache_read_input_tokens or cache_creation_input_tokens value that is non-zero is the only confirmation that counts.

Tools count toward the span — and that can rescue you

One asymmetry works in your favour. The cacheable span is not the system prompt alone: tool definitions serialize into it, ahead of the system prompt, and their tokens count toward the minimum. We measured one agent whose system prompt was 874 tokens — hopeless against a 1,024 floor on its own — but whose tool definitions brought the true span to 1,401 tokens. It cached. An engineer checking only the system prompt would have written it off.

The same fact has a sharp edge, covered in the tool-ordering post: tools sitting at the front of the span means their bytes must be as stable as the prompt's, or nothing downstream of them ever matches. Count them for the minimum; discipline them for the match.

Below the floor is a threshold problem, not a defect

The last thing worth internalising: being under the minimum is the one cache blocker that fixes itself. A prompt with a timestamp at its top stays broken until someone moves the timestamp. A prompt that is merely short becomes eligible the day it grows — more instructions, another tool, a few examples — with no restructuring at all. Vigil's injector encodes that distinction explicitly: every skip carries a verdict, and below_model_minimum is classed threshold ("nothing is wrong with this prompt; it does not qualify yet") while volatility reasons are classed structural ("this prompt must change"). The two demand opposite advice, and collapsing them into one "not eligible" boolean is how a customer ends up rewriting a prompt that was about to qualify on its own. If you route through Vigil, the per-agent skip reason names which side of that line each agent is on.

What to do

Look up the published cache minimum for the exact models you run — do not infer it from a sibling model, and re-check it when you upgrade generations, because the value moves in both directions. Then estimate your real span: serialized tools plus system prompt, divided by 4, and if the result is within 10% of the minimum, confirm against the response's usage fields rather than trusting the estimate. Finally, if a prompt is under the floor, weigh simply leaving it uncached — below 1,024 tokens the absolute saving is small, and the write premium on a span that barely clears the bar can eat most of it.