Prompt caching only pays when the prefix stays byte-identical. Nothing throws when it breaks - you still get an answer; you pay full price plus write premium. Anthropic’s minimum cacheable prefix is model-dependent and does not track tier or recency: 512 tokens on Opus 5, 1,024 on the Sonnet 5 below, 4,096 on Haiku 4.5. Shorter prefixes silently do not cache, so the same prefix can read fine here and never cache once you fan the work out to a cheaper tier. You get four cache_control breakpoints maximum per request.
def check_cache(build_request, n=2):
"""Call the same request n times; the prefix is healthy if call 2+ reads."""
for i in range(1, n + 1):
u = client.messages.create(**build_request()).usage
print(
f"call {i}: write={u.cache_creation_input_tokens} "
f"read={u.cache_read_input_tokens} uncached={u.input_tokens}"
)
if i > 1:
assert u.cache_read_input_tokens > 0, "prefix changed or under minimum"
assert u.cache_creation_input_tokens == 0, "prefix rewritten every call"
check_cache(lambda: dict(
model="claude-sonnet-5",
max_tokens=64,
system=[{"type": "text", "text": SYSTEM_PROMPT,
"cache_control": {"type": "ephemeral"}}],
tools=TOOLS,
messages=[{"role": "user", "content": "ping"}],
))
Healthy: write on call 1, read on call 2. When reads stay at zero, diff the two payloads - the byte that moved is rarely the one you suspect. Placement rules live in Cache-stable prefix. Full playbook: Don’t break the prompt cache.