Bug Description
isStale() (lib/interceptor/cache.js:65-91) grants the request max-stale grace window without
consulting the stored response's directives. RFC 9111 §5.2.2.2: a cache MUST NOT use a stale
response with must-revalidate to satisfy any request without successful validation — this
overrides max-stale (§5.2.1.2 note) and also excludes it from stale-if-error (RFC 5861 §4).
proxy-revalidate (§5.2.2.8) has the same semantics for shared caches — which is the
interceptor's default type — and is currently parsed but never enforced.
Repro: store 200 Cache-Control: max-age=1, must-revalidate (+ ETag); wait >1s; request with
Cache-Control: max-stale=600 → observed: served from cache, zero origin contact
(undici 8.7.0, current main, Node 22); expected: conditional request to the origin.
Suggested fix
Skip the max-stale grace in isStale() when
result.cacheControlDirectives['must-revalidate'] (or proxy-revalidate with type: 'shared'),
and exclude such responses from the stale-if-error threshold in handleResult. ~5-10 LOC + tests.
Found during an agent-assisted HTTP-caching review for @jeswr; every claim reproduced on undici 8.6.0 (repo) and 8.7.0 (npm) on Node 22.23.1. Fix PR to follow.
Bug Description
isStale()(lib/interceptor/cache.js:65-91) grants the requestmax-stalegrace window withoutconsulting the stored response's directives. RFC 9111 §5.2.2.2: a cache MUST NOT use a stale
response with
must-revalidateto satisfy any request without successful validation — thisoverrides
max-stale(§5.2.1.2 note) and also excludes it from stale-if-error (RFC 5861 §4).proxy-revalidate(§5.2.2.8) has the same semantics for shared caches — which is theinterceptor's default
type— and is currently parsed but never enforced.Repro: store
200 Cache-Control: max-age=1, must-revalidate(+ ETag); wait >1s; request withCache-Control: max-stale=600→ observed: served from cache, zero origin contact(undici 8.7.0, current main, Node 22); expected: conditional request to the origin.
Suggested fix
Skip the max-stale grace in
isStale()whenresult.cacheControlDirectives['must-revalidate'](orproxy-revalidatewithtype: 'shared'),and exclude such responses from the stale-if-error threshold in
handleResult. ~5-10 LOC + tests.Found during an agent-assisted HTTP-caching review for @jeswr; every claim reproduced on undici 8.6.0 (repo) and 8.7.0 (npm) on Node 22.23.1. Fix PR to follow.