From d0667e4aef63af067da7b078dc615b2c218824f1 Mon Sep 17 00:00:00 2001 From: Nicolas Gayerie Date: Thu, 6 Aug 2026 09:28:47 +0000 Subject: [PATCH 1/3] Document CDN-Cache-Control in BYPASS causes, clarify Age callout - Add a BYPASS bullet documenting Cloudflare-CDN-Cache-Control and CDN-Cache-Control, and their precedence over Cache-Control. An origin returning cacheable Cache-Control alongside a non-cacheable CDN-Cache-Control directive produces BYPASS, and readers otherwise have no signal that these two headers even exist as BYPASS causes. - Rewrite the Age callout and HIT confirmation to describe the Tiered Cache lower-tier fill in plain language, without referring to the internal CacheTieredFill=true field. That field is only visible in the http_requests Logpush dataset, not in HTTP responses, so it is not something readers can inspect. --- src/content/docs/cache/concepts/cache-responses.mdx | 3 ++- .../cache/troubleshooting/investigating-uncached-responses.mdx | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/content/docs/cache/concepts/cache-responses.mdx b/src/content/docs/cache/concepts/cache-responses.mdx index 815fc8beabd..e25b77312c5 100644 --- a/src/content/docs/cache/concepts/cache-responses.mdx +++ b/src/content/docs/cache/concepts/cache-responses.mdx @@ -15,7 +15,7 @@ The `CF-Cache-Status` header output indicates whether a resource is cached or no :::note[`Age` response header] The `Age` response header is a header returned from cache that specifies the time in seconds that an asset has been in Cloudflare's cache. This value resets if the asset is revalidated, purged, or evicted and then re-cached. -The `Age` header is only present for responses served from the cache. It will not appear on a cache MISS, dynamic traffic, the first request that populates the lower tier HIT from tiered cache `CacheTieredFill=true` or any responses that did not originate from the cache (for example, responses generated by a Worker that bypassed the cache). +The `Age` header is only present for responses served from the cache. It will not appear on a cache MISS, dynamic traffic, the first request that populates a lower-tier data center's cache from an upper tier via [Tiered Cache](/cache/how-to/tiered-cache/), or any responses that did not originate from the cache (for example, responses generated by a Worker that bypassed the cache). ::: Below you can find a comprehensive breakdown of Cloudflare's cache response statuses. @@ -55,6 +55,7 @@ Cloudflare considered the asset eligible for cache at request time — either be Common reasons the origin response is treated as not cacheable include: * The response exceeds the [maximum cacheable file size](/cache/concepts/default-cache-behavior/#cacheable-size-limits) for your plan. +* The origin returned a `Cloudflare-CDN-Cache-Control` or `CDN-Cache-Control` header with a non-cacheable directive. Cloudflare evaluates these headers ahead of `Cache-Control`, in the precedence `Cloudflare-CDN-Cache-Control` > `CDN-Cache-Control` > `Cache-Control`. For example, an origin returning both `Cache-Control: public, max-age=3600` and `CDN-Cache-Control: no-store` produces `BYPASS`. Inspect every response header, not just `Cache-Control`. Refer to [CDN-Cache-Control](/cache/concepts/cdn-cache-control/) for the precedence rules. * The origin returned `Cache-Control: no-store` or `private`. These directives prevent caching in either [Origin Cache Control](/cache/concepts/cache-control/) mode. * The origin returned `Cache-Control: no-cache`, `max-age=0`, or `s-maxage=0`, and [Origin Cache Control](/cache/concepts/cache-control/) is disabled (the default on Enterprise plans). With Origin Cache Control enabled (the default on Free, Pro, and Business plans), these directives cause Cloudflare to cache and revalidate the response instead, producing [`REVALIDATED`](#revalidated) or [`EXPIRED`](#expired). Refer to [Understand `no-store` and `no-cache` directives](/cache/concepts/cache-control/#understand-no-store-and-no-cache-directives) and the [Conditions](/cache/concepts/cache-control/#conditions) table. * The origin returned a `Set-Cookie` header. Refer to [Interaction of `Set-Cookie` response header with Cache](/cache/concepts/cache-behavior/#interaction-of-set-cookie-response-header-with-cache) for the specific configurations that produce `BYPASS`. diff --git a/src/content/docs/cache/troubleshooting/investigating-uncached-responses.mdx b/src/content/docs/cache/troubleshooting/investigating-uncached-responses.mdx index 89e5b9f68e9..a962b26e53f 100644 --- a/src/content/docs/cache/troubleshooting/investigating-uncached-responses.mdx +++ b/src/content/docs/cache/troubleshooting/investigating-uncached-responses.mdx @@ -40,6 +40,7 @@ Once the request is eligible, subsequent responses reflect the response-time dec The request was eligible for cache, but the origin response or configuration prevented Cloudflare from storing it. Common causes: - **The response exceeds the [cacheable size limit](/cache/concepts/default-cache-behavior/#cacheable-size-limits) for your plan.** Split the object into smaller assets, or move to a plan with a higher limit. [R2](/r2/) is an origin storage alternative — it does not raise the CDN cacheable size limit. +- **The origin returned a `Cloudflare-CDN-Cache-Control` or `CDN-Cache-Control` header with a non-cacheable directive.** Cloudflare evaluates these headers ahead of `Cache-Control`, in the precedence `Cloudflare-CDN-Cache-Control` > `CDN-Cache-Control` > `Cache-Control`. For example, an origin returning both `Cache-Control: public, max-age=3600` and `CDN-Cache-Control: no-store` produces `BYPASS`. Inspect every response header, not just `Cache-Control`. Refer to [CDN-Cache-Control](/cache/concepts/cdn-cache-control/) for the precedence rules. - **The origin returned `Cache-Control: no-store` or bare `private`.** These directives block caching in either [Origin Cache Control](/cache/concepts/cache-control/) mode by default. Two exceptions: `Cache-Control: private="
"` with field names remains cacheable — Cloudflare drops only the named headers. And a [Cache Rule](/cache/how-to/cache-rules/) with an Edge TTL that ignores origin cache-control (**Edge TTL → Ignore cache-control header and use this TTL** or **Status code TTL**) overrides both directives, so a response with `no-store` plus that Edge TTL setting is cached. - **The origin returned `Cache-Control: no-cache`, `max-age=0`, or `s-maxage=0`, and [Origin Cache Control](/cache/concepts/cache-control/) is disabled** (the default on Enterprise plans). With Origin Cache Control enabled (the default on Free, Pro, and Business plans), these directives cause Cloudflare to cache and revalidate the response instead, producing [`REVALIDATED`](/cache/concepts/cache-responses/#revalidated) or [`EXPIRED`](/cache/concepts/cache-responses/#expired). Refer to [Understand `no-store` and `no-cache` directives](/cache/concepts/cache-control/#understand-no-store-and-no-cache-directives) and the [Conditions](/cache/concepts/cache-control/#conditions) table. - **The origin returned a `Set-Cookie` header.** By default, Cloudflare does not cache responses that include `Set-Cookie`. To cache the response, use one of the following: @@ -81,7 +82,7 @@ If your requests reach different Cloudflare data centers, each produces its own After adjusting configuration, request the URL twice from the same client and verify the expected outcome for your configuration: -- **Fresh, positive Edge TTL:** `cf-cache-status: HIT` and an `Age` header that increases on subsequent requests. `Age` may be absent on the first lower-tier request that populates the local cache from a tiered cache fill (`CacheTieredFill=true`). +- **Fresh, positive Edge TTL:** `cf-cache-status: HIT` and an `Age` header that increases on subsequent requests. `Age` may be absent on the first request served by a lower-tier data center after it populates its cache from an upper tier via [Tiered Cache](/cache/how-to/tiered-cache/); subsequent requests include it. - **Origin returns `Cache-Control: no-cache` with [Origin Cache Control](/cache/concepts/cache-control/) enabled:** `cf-cache-status: REVALIDATED` when the origin confirms the cached copy is unchanged, or [`EXPIRED`](/cache/concepts/cache-responses/#expired) when the origin returns new content. Both indicate the response is cached. `must-revalidate` on its own does not force revalidation on every request — it only prevents serving stale content after the freshness TTL expires. If the response is still `MISS` or `BYPASS` after these checks, capture two full responses (request and response headers, including `cf-ray` values) and open a support case. The `cf-ray` values are required to trace the request through the Cloudflare network. From 2b0ee5a9dec9d0b1030c46648f2588c41bf87f8c Mon Sep 17 00:00:00 2001 From: Nicolas Gayerie Date: Thu, 6 Aug 2026 09:45:25 +0000 Subject: [PATCH 2/3] Split semicolon into two sentences per style guide Address SG-619a15c3d17a from the docs bot review. --- .../cache/troubleshooting/investigating-uncached-responses.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/docs/cache/troubleshooting/investigating-uncached-responses.mdx b/src/content/docs/cache/troubleshooting/investigating-uncached-responses.mdx index a962b26e53f..2096d1ab513 100644 --- a/src/content/docs/cache/troubleshooting/investigating-uncached-responses.mdx +++ b/src/content/docs/cache/troubleshooting/investigating-uncached-responses.mdx @@ -82,7 +82,7 @@ If your requests reach different Cloudflare data centers, each produces its own After adjusting configuration, request the URL twice from the same client and verify the expected outcome for your configuration: -- **Fresh, positive Edge TTL:** `cf-cache-status: HIT` and an `Age` header that increases on subsequent requests. `Age` may be absent on the first request served by a lower-tier data center after it populates its cache from an upper tier via [Tiered Cache](/cache/how-to/tiered-cache/); subsequent requests include it. +- **Fresh, positive Edge TTL:** `cf-cache-status: HIT` and an `Age` header that increases on subsequent requests. `Age` may be absent on the first request served by a lower-tier data center after it populates its cache from an upper tier via [Tiered Cache](/cache/how-to/tiered-cache/). Subsequent requests include it. - **Origin returns `Cache-Control: no-cache` with [Origin Cache Control](/cache/concepts/cache-control/) enabled:** `cf-cache-status: REVALIDATED` when the origin confirms the cached copy is unchanged, or [`EXPIRED`](/cache/concepts/cache-responses/#expired) when the origin returns new content. Both indicate the response is cached. `must-revalidate` on its own does not force revalidation on every request — it only prevents serving stale content after the freshness TTL expires. If the response is still `MISS` or `BYPASS` after these checks, capture two full responses (request and response headers, including `cf-ray` values) and open a support case. The `cf-ray` values are required to trace the request through the Cloudflare network. From 7ebf475108871389f69dc9ca20bb620f14202167 Mon Sep 17 00:00:00 2001 From: Nicolas Gayerie Date: Thu, 6 Aug 2026 11:32:35 +0000 Subject: [PATCH 3/3] Refine Age header definition per review Clarify that Age is per-data-center scope: the seconds since the serving data center's local cache admitted or last revalidated the object, rather than the vaguer 'time in Cloudflare's cache'. Applies @foreseaz's suggestion. --- src/content/docs/cache/concepts/cache-responses.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/docs/cache/concepts/cache-responses.mdx b/src/content/docs/cache/concepts/cache-responses.mdx index e25b77312c5..bd6cf05ab80 100644 --- a/src/content/docs/cache/concepts/cache-responses.mdx +++ b/src/content/docs/cache/concepts/cache-responses.mdx @@ -13,7 +13,7 @@ head: The `CF-Cache-Status` header output indicates whether a resource is cached or not. To investigate cache responses returned by this header, use services like [Redbot](https://redbot.org/), [webpagetest.org](http://www.webpagetest.org/), or a visual tool like [Cloudflare Optics plugin](https://chromewebstore.google.com/detail/cloudflare-optics/mdjgbjnbdnhneejmmaabmccfehigbjbe). :::note[`Age` response header] -The `Age` response header is a header returned from cache that specifies the time in seconds that an asset has been in Cloudflare's cache. This value resets if the asset is revalidated, purged, or evicted and then re-cached. +The `Age` response header is returned when Cloudflare serves a response from a local cache object on the data center handling the request. It is the number of seconds since that object was admitted or last revalidated at that cache. It resets if the asset is revalidated, purged, or evicted and then re-cached. The `Age` header is only present for responses served from the cache. It will not appear on a cache MISS, dynamic traffic, the first request that populates a lower-tier data center's cache from an upper tier via [Tiered Cache](/cache/how-to/tiered-cache/), or any responses that did not originate from the cache (for example, responses generated by a Worker that bypassed the cache). :::