Troubleshooting the cache

Find out why a response isn't cached, why visitors still see old content after a change, and why Early Hints don't appear.

On this page

Start with the response headers of the URL:

curl -sI https://www.example.com/path | grep -i -E 'x-cache-status|cache-status|age|cache-control|set-cookie|vary'

Cache-Status says why in detail; every value is in Cache status headers.

No X-Cache-Status header

The cache wasn't involved: the answer came from the edge itself (a WAF block, a challenge, the access gate or a redirect), or the name isn't proxied through OpenWAF. Check that the request reaches the edge and, after a settings change, that the new version has propagated (Changes › Propagation).

Always DYNAMIC

detailFix
extensionThe file type isn't in the default list. Add a cache rule for it (HTML, JSON…).
ruleA bypass rule matches. Remember the last matching rule wins.
dev-modeDevelopment mode is on for the zone or the name.
disabledThe cache is off for this name: check Scope, a name can have its own value.
queryCaching level is No query string and the URL has a query.
varyThe request carries a header listed in a rule's vary_bypass_if_present.
method, upgrade, bodyOnly GET and HEAD without a body are cached.
pathThe path contains ;, an encoded / or \, or ends a segment with a dot.

Always MISS or BYPASS

detailFix
set-cookieThe origin sets a cookie on this response. Stop setting it on public assets, send Cache-Control: private="Set-Cookie", or use a rule with edge_ttl.mode override if the page is the same for everyone.
private, no-storeThe origin's Cache-Control forbids shared caches. Send public, max-age=…, or target the edge with OpenWAF-CDN-Cache-Control.
uncacheableNo Cache-Control, Expires or default TTL applies, typically HTML made eligible by a rule. Have the origin send freshness or set an edge TTL in the rule.
varyThe origin sends Vary with a header other than Accept-Encoding, Accept (images) or Origin. Remove it, or list it in a rule's vary_bypass_if_present.
authThe request had Authorization; the response must say public, s-maxage or must-revalidate to be shared.
sizeLarger than cache.max_object_mb. Raise it (up to 512).
deceptionThe content type doesn't match the extension. Fix the origin's Content-Type.
personalA document (pdf, docx…) requested with cookies, without explicit freshness from the origin.
statusThe status code can't be stored.

A MISS on the second request can also mean it reached another edge node: each node has its own cache.

Visitors still see old content

  • Purge the URLs, a prefix, the hostname or a tag. Check Recent purges shows it applied on every node.
  • With a URL purge, the query string counts: app.css?v=2 and app.css are different URLs.
  • Browsers may keep their own copy for the max-age they received. A purge can't clear browser caches; use versioned asset names or shorter max-age values.
  • After a deploy of a site with hashed assets, purge the HTML: old pages point to the previous build's files.

Purge answers 429

The organization hit the purge limits. Wait for the Retry-After seconds, or group values: one purge can carry up to 100 values, and a prefix or tag often replaces many URLs.

No 103 Early Hints

  • The page was served from the cache (HIT): hints are only sent when the request waits for the origin.
  • The node hasn't seen a shareable 200 HTML answer for the page yet; request it again.
  • The request isn't a navigation: it needs Accept: text/html, GET, no Range, HTTP/1.1 or HTTP/2.
  • The links point to an origin not listed in early_hints.extra_origins, or aren't https.

See Early Hints.

Last updated:

↑↓ to navigate↵ to openesc to close