Dated report · 13 Oct 2026 · HTTP caching standards
Negative caching of missing versioned assets
Why a 404 or 410 for a versioned asset can be reused after deployment, what HTTP does and does not specify, and which evidence helps distinguish an HTTP cache from a worker or application.
Answer first
RFC 9110 identifies both 404 Not Found and 410 Gone as heuristically cacheable; unless another rule applies, caches may use such responses to satisfy eligible GET or HEAD requests. This does not require a cache to store either status, assign a specific heuristic lifetime, or produce a cache hit. A 404 does not say whether absence is temporary or permanent. A 410 communicates that unavailability is likely permanent, but it is neither a universal permanence guarantee nor a required status for every permanent removal.
Practical implication, not an observed deployment result: if a cache stores a 404 for /assets/app.v7.js, a later restoration of bytes at that same URI may remain hidden while the stored negative response is fresh. Expiry, validation, or an applicable cache-specific removal can change that result. The actual cache key, storage decision, freshness policy, path, and downstream copies are unknown without a trace.
What 404 and 410 say
| Status | HTTP meaning | Cache boundary |
|---|---|---|
404 Not Found | The origin server did not find a current representation for the target resource, or is unwilling to disclose that one exists. The status does not distinguish temporary from permanent absence. | Heuristically cacheable; an HTTP cache may reuse it, but actual storage and lifetime are not specified by the status alone. |
410 Gone | The origin server indicates that access is no longer available and is likely to be permanent. A server need not use 410 for every permanently unavailable resource. | Also heuristically cacheable. “Likely permanent” is status meaning, not a required cache lifetime. |
These are response semantics from the server that generated the status. A browser-visible 404 does not, on its own, establish that the origin generated it: an intermediary, service worker, or application path may be involved.
Cacheable is not the same as cached
RFC 9111 §3 makes storage conditional. Among other requirements, a cache must understand the request method and final status, the response must not prohibit storage with no-store, and at least one basis for storage must apply. A heuristically cacheable status such as 404 or 410 can supply that basis. The RFC does not make storage mandatory; it also notes that a cache may decline to store a response lacking a validator and explicit expiration even where storage is permitted.
For a response otherwise eligible for storage, explicit freshness takes precedence: a shared cache uses s-maxage when present, then the applicable max-age or Expires rules. If explicit freshness is absent, an HTTP cache may apply a heuristic to a heuristically cacheable response. The standard gives no universal heuristic algorithm or negative-response TTL. A time cannot be calculated from the 404/410 status alone.
| Directive on a 404/410 response | Relevant standard effect | Does it purge an older stored 404? |
|---|---|---|
Cache-Control: no-store | A compliant HTTP cache must not store or use this response to satisfy another request. | No. It governs this response; it is not retroactive deletion. |
Cache-Control: no-cache | A cache may store the response but must validate it before reuse. | No. |
Cache-Control: max-age=N | Provides an explicit freshness lifetime for caches to which it applies. | No. |
Cache-Control: s-maxage=N | For shared caches, overrides max-age/Expires and requires validation after staleness. | No. |
| No explicit freshness | A cache may choose heuristic freshness; neither status supplies a standard TTL. | No defined purge effect. |
A newly deployed no-store response cannot be treated as a command to delete an older stored 404. If a cache revalidates an older negative response and receives a suitable 304, it may update and reuse the stored representation; the 304 has no new response body and does not establish that the asset bytes were returned.
When the missing file returns
Suppose stale HTML requests /assets/app.v7.js, and some cache stores a 404. A later deployment makes bytes available at that exact URI. If the stored response still matches the request and is considered fresh, the cache can satisfy the request with the stored response until the applicable freshness/validation rules or an effective removal change the state. This is an inference from URI-based cache reuse, not evidence that a particular cache stored the response or will serve it.
Publishing changed bytes under a new fingerprinted URI ordinarily avoids reuse of the old URI's response under normal HTTP matching. It does not clear the old URL, guarantee that application routing requests the new URL, or prove that every custom cache uses the expected key. Preserve old asset URLs for the supported compatibility window if older pages or workers may still request them; the existing deployment and service-worker reports cover those broader release choices.
Do not infer a purge from a later response
RFC 9111 §4.4 requires a cache to invalidate its stored response(s) for the target URI when it receives a 2xx or 3xx response to an unsafe request method that passed through that cache. The rule is limited to caches the state-changing request traverses. It does not establish global invalidation.
A later ordinary GET returning the asset, a deployment that bypasses a cache, or a no-store directive on a new response does not invoke that mandatory unsafe-method rule. Provider purge APIs and deployment hooks are separate product/configuration behavior; use the existing provider reports for those details rather than generalizing them into HTTP semantics.
Evidence that narrows the source
Record the exact failing URL (including query), method, time, initiator, redirect chain, status, body, and request/response headers. Compare the request with the page or manifest build that named the asset. Keep each observation scoped to the hop or tool that produced it.
| Possible source | Useful evidence | What it does not establish |
|---|---|---|
| HTTP cache or intermediary | A trusted named Cache-Status member and per-hop cache logs; record Age, Date, response directives, validators, request conditionals, and Vary where visible. | Age alone does not identify the cache or hop. An absent field or zero age does not by itself disprove reuse. A copied or synthesized field is not authenticated provenance. |
| Current origin response | Correlate the exact URI and request ID/time with an origin log or marker and compare the deployed manifest/files. | A response from the next inbound server may be an intermediary answer. An uncorrelated browser status or missing origin log does not identify the producer. |
| Service worker / Cache Storage | In DevTools, inspect whether a worker handled the request and check the exact request URL in script-managed Cache Storage and the active fetch handler. | Service-worker Cache Storage is separate from the browser HTTP cache; a worker-bypass experiment does not bypass every intermediary. |
| Application-level error | Check whether a network request occurred, its actual response, and the app's fallback/manifest-loader or storage logic. | UI text saying “404” may not equal the HTTP response status; an application can construct its own error result. |
Age is estimated response age accumulated across cache residence and transit, not a hop label. RFC 9211's optional Cache-Status is more discriminating when a known cache emits it and the field is intact; it is not guaranteed to appear or cryptographically authenticate its emitter. Correlation across browser, named intermediary, and origin is stronger than any single header.
Source register
- RFC 9110 §15.5.5 — 404 Not Found and §15.5.11 — 410 Gone: status semantics and heuristic cacheability.
- RFC 9111 §3 — Storing Responses in Caches: storage constraints and cacheability bases.
- RFC 9111 §4.2.1 — Calculating Freshness Lifetime, §4.2.2 — Calculating Heuristic Freshness, and §4.2.3 — Calculating Age.
- RFC 9111 §4.3 — Validation, §4.3.4 — Freshening Stored Responses upon Validation, and §4.4 — Invalidating Stored Responses.
- RFC 9111 §5.2.2.4 — no-cache, §5.2.2.5 — no-store, and §5.2.2.10 — s-maxage.
- RFC 9211 §2 — Cache-Status: optional named-cache response evidence.
- W3C Service Workers, 17 Sep 2026 Candidate Recommendation Draft, §§4.6.7 and 5: fetch-handler responses and script-managed Cache objects. This is a work-in-progress draft, not a W3C Recommendation.
- Chrome DevTools Network reference and Application panel overview: Chrome-specific inspection affordances.
- Developer-facing cross-checks: MDN Cache-Control, HTTP caching, conditional requests, and 304 Not Modified. RFCs remain the normative source for HTTP claims.
Limits and related work
No live endpoint, browser, CDN, provider, origin, or cache was used. No response headers, logs, purge, deployment, application, Cache Storage entry, or analytics were observed. This report does not claim that every cache stores negative responses, describe a particular provider/browser behavior, establish deployment provenance, or treat Age as identifying a hop. The actual key, selected lifetime, cache hit, and post-restoration result require an authorized trace.
For adjacent questions, see When stale HTTP content is allowed, the service-worker update report, the deployment and incident runbook, and the provider-specific CloudFront and Cloudflare reports.