You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
cache: ctx.request.headers and getRequestContext().cookie()/cookies()/theme bypass the cache and capture identity guards #976
The identity guards stop cookies(), headers() and non-cacheable variables from baking one visitor's data into a shared entry: a PPR capture, a route cache() miss, "use cache", and a loader's own cache() without key() (#972). Three raw read paths bypass all of them:
ctx.request.headers, in handlers, loaders and "use cache" bodies that receive ctx. ctx.request is the same Request object everywhere: request-context.ts:1184, loader-resolution.ts:529, handler-context.ts:266, middleware.ts:246. "use cache" keys a Request by URL only (cache-runtime.ts:487), so a header-derived value can bake into a shared entry.
The router reads request.headers itself in about 24 source files, e.g. request-context.ts:1043 and the state-cookie read near :1290.
Wrapping the Request in a Proxy breaks fetch(ctx.request), new Request(ctx.request) and clone().
A workable shape is a headers accessor on the exposed request that checks the same scopes at access time. key() and "use cache" key-building run outside those scopes, so a keyed read keeps working. The router's own reads would move to a raw reference.
Breaking for "use cache" bodies that read ctx.request.headers today.
Proposal
Guard the three raw paths with the same scope checks as cookies()/headers(), and document the raw Request escape hatch, if any. Until then, the loader and caching skills say these reads are unguarded and must be part of key().
Decision: guard all raw request-identity reads exactly like cookies()/headers(). That covers ctx.request.headers (handlers, loaders, "use cache" bodies that receive ctx) and getRequestContext().cookie()/cookies(). Inside a cache() boundary, "use cache", or an unkeyed loader cache() fill, the read throws or fails. During a PPR capture it refuses the capture. key() is unaffected. This is a breaking change for handlers under cache()/ppr that read raw headers; the error names the fix: middleware, a live loader, or include the value in key(). Scheduled after the guard unification in the simplify pass.
Activity
ivogt commentedon Sep 30, 2026
Decision: guard all raw request-identity reads exactly like
cookies()/headers(). That coversctx.request.headers(handlers, loaders,"use cache"bodies that receivectx) andgetRequestContext().cookie()/cookies(). Inside acache()boundary,"use cache", or an unkeyed loadercache()fill, the read throws or fails. During a PPR capture it refuses the capture.key()is unaffected. This is a breaking change for handlers undercache()/pprthat read raw headers; the error names the fix: middleware, a live loader, or include the value inkey(). Scheduled after the guard unification in the simplify pass.fix(router)!: ctx.request.headers and getRequestContext().cookie()/co…
ivogt commentedon Sep 30, 2026
Fixed in #999 (35c0ae5).