---
title: "CDN Cache Misses: How to Find and Fix the Real Causes"
description: "Learn how to distinguish a real cache miss from a bypass or revalidation, find the root cause, and improve CDN cache efficiency without caching private data."
canonical_url: https://optimi.com/en/guides/cdn-cache-misses
md_url: https://optimi.com/en/guides/cdn-cache-misses.md
last_updated: 2026-07-14
---

# CDN Cache Misses: How to Find and Fix the Real Causes

A cache miss is a symptom. The fix depends on whether the object is absent, expired, uncacheable, or keyed differently than you expect.

Fix CDN cache misses by first classifying the response, then tracing its cacheability and cache key. Do not raise a TTL or enable broad HTML caching as a first reaction. A response can be a legitimate miss, a deliberate bypass, a revalidation, or a cache entry that is fragmented across URLs and headers. The safe goal is not the highest hit ratio; it is the lowest origin work consistent with correct and private responses.

An edge cache stores a representation under a key. On a request, it checks whether the key matches, whether the stored response is fresh, and whether policy allows reuse. If not, it contacts the origin or another cache tier. The origin response then either populates the cache, updates an existing entry, or remains uncacheable.

> **Do not optimize the wrong number**
>
> A higher hit ratio can look better while users still wait on slow misses, and a lower ratio can be correct when most traffic is private or intentionally dynamic. Segment cache performance by URL class, status, region, and provider.

## Identify the cache outcome

Inspect response headers from more than one location and repeat the same request. With Cloudflare, `CF-Cache-Status` distinguishes common outcomes such as `HIT`, `MISS`, `EXPIRED`, `REVALIDATED`, `UPDATING`, `STALE`, `BYPASS`, and `DYNAMIC`. `Age` is additional evidence that a response came from a cache. With Fastly, inspect `X-Cache`, `X-Served-By`, `Age`, and your configured log fields. Provider labels and aggregation rules differ, so do not compare them as if they were one standard metric.

Use a request with a fixed URL, method, host, and relevant headers. Send it twice from the same test location, then from a second location. A first-request miss followed by a hit is normal cache fill. A miss on every request suggests a key mismatch, a non-cacheable response, a bypass rule, an object too large for the configured cache, or a request path that never reaches the expected cache.

Revalidation is different from a full miss. The cache has an object but must ask the origin whether it changed, often using `ETag` or `Last-Modified`. A 304 response can save the body transfer but still costs an origin request and round trip. `stale-while-revalidate` can serve a stale response while updating in the background, if its semantics are appropriate.

**Classify a repeated cache miss before changing the TTL**

![Troubleshooting flow that starts with two identical requests and distinguishes normal fill from a repeated miss. A repeated miss is then classified as a bypass or uncacheable response, a cache-key mismatch, a cold or evicted object, or a request path that never reaches the expected cache.](/diagrams/cdn-cache-misses/miss-classification.svg)

*Repeated misses need a cause-specific fix; extending freshness cannot repair a bypass rule, a fragmented key, or an unsafe response.*

## Find the real cause

### The response is not cacheable

Check the origin response for `Cache-Control: private`, `no-store`, or `no-cache`, and for `Set-Cookie`. Check whether the request carries `Authorization`, whether the method is GET or HEAD, and whether the status is eligible for storage. A dynamic response is often correct: account pages, cart contents, payment steps, and personalized recommendations should not be shared accidentally.

For public content, return an explicit policy rather than relying on heuristic freshness. A typical immutable asset might use a long `max-age` with a fingerprinted filename. A public HTML response may use a shorter shared-cache lifetime and revalidation. `s-maxage` can separate shared-cache freshness from browser freshness. `stale-if-error` may protect a public page during a temporary origin failure, but it must not mask dangerous or time-sensitive changes.

### The cache key is too broad or too narrow

Query strings are frequent offenders. Analytics parameters can create many keys for one representation, while language, currency, device, or content experiment parameters may genuinely change it. Headers named by `Vary`, cookies, authorization, hostnames, and URL normalization can also split the cache. Document every key component and remove only values proven not to affect the response.

Cloudflare equivalents include Cache Rules, custom cache keys, Cache Analytics, and Trace. Fastly equivalents include VCL hash logic, surrogate keys for invalidation, and shielding. Keep the provider-neutral key model in source control and review it with the application team. Never remove a user or tenant discriminator from a key to improve a dashboard metric.

### The object is cold, expired, or evicted

A low-traffic object can expire before its next request. A deploy or purge can make a whole site cold. A large object or memory pressure can lead to eviction. In a multi-POP CDN, one location can miss while another has the object. Tiered caching or shielding can reduce the number of origin fills, but it does not make every edge POP hold every object.

If content is published predictably, warm a small set of public URLs with a controlled process. Prefer versioned filenames and targeted purge over purging an entire site. Longer TTLs reduce fills but increase staleness risk, so pair them with a reliable invalidation method.

### The request never reaches the cache

A worker, edge function, redirect, WAF action, or application middleware may run before the cache. A cache rule may be ordered after a bypass rule. A different hostname, protocol, path, or origin route may be serving the test. Trace the request through the provider and compare edge logs with origin logs.

## A safe troubleshooting workflow

1. Pick a public, deterministic URL and record status, response headers, content length, and body version.
2. Repeat the request with and without harmless tracking parameters, then with relevant language or device headers.
3. Compare a cold request with the second request from the same POP or test region.
4. Inspect origin headers, provider rules, cache-key configuration, and purge history together.
5. Fix one cause in a narrow path, then verify privacy, content correctness, origin request rate, and cache status.
6. Roll the change out by hostname, path, or region before applying it globally.

## Observe what users experience

Track hit, miss, bypass, revalidation, and stale rates separately. Break them down by route, status code, response size, region, CDN, cache key version, and deployment. Correlate cache outcomes with origin CPU, bandwidth, TTFB, and error rate. Sample full headers in logs, but protect cookies, authorization values, and personal data.

Mistakes include caching all HTML, treating `no-cache` as `no-store`, ignoring `Set-Cookie`, stripping every query string, measuring only aggregate hit ratio, purging on every deploy, and assuming a provider's `HIT` means the browser did not make a request. A [CDN](/en/performance/cdn) reduces origin work when policy is correct; [Multi-CDN](/en/performance/multicdn) adds another cache and purge consistency problem to solve.

For standards-based behavior, read [RFC 9111 HTTP Caching](https://www.rfc-editor.org/rfc/rfc9111). For implementation details, use [Cloudflare cache responses](https://developers.cloudflare.com/cache/concepts/cache-responses/) and [Fastly shielding](https://www.fastly.com/documentation/guides/concepts/shielding/). [Contact Optimi](/en/contact) if you need a cache-key and origin-load review.

> There are only two hard things in Computer Science: cache invalidation and naming things.

[Review your cache](/en/contact): Turn cache misses into useful signals — Talk to our team about cache keys, TTLs, purges, shielding, and observability across your delivery stack.
