mirror of
https://github.com/cloudflare/vinext.git
synced 2026-05-09 08:25:34 +02:00
[PR #907] [MERGED] fix(app-router): fixing cache request leaks #936
Labels
No labels
enhancement
enhancement
good first issue
help wanted
nextjs-tracking
nextjs-tracking
pull-request
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
starred/vinext#936
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
📋 Pull Request Information
Original PR: https://github.com/cloudflare/vinext/pull/907
Author: @NathanDrake2406
Created: 4/26/2026
Status: ✅ Merged
Merged: 4/29/2026
Merged by: @james-elicx
Base:
main← Head:nathan/cache-isolation-fixes📝 Commits (1)
f0f741afix app router cache request leaks📊 Changes
18 files changed (+1054 additions, -151 deletions)
View changed files
📝
packages/vinext/src/entries/app-rsc-entry.ts(+30 -14)📝
packages/vinext/src/server/app-page-cache.ts(+36 -1)📝
packages/vinext/src/server/app-page-render.ts(+3 -4)📝
packages/vinext/src/server/app-route-handler-cache.ts(+6 -0)📝
packages/vinext/src/server/app-route-handler-execution.ts(+35 -3)📝
packages/vinext/src/server/app-route-handler-runtime.ts(+172 -1)➕
packages/vinext/src/server/app-static-generation.ts(+54 -0)📝
packages/vinext/src/shims/headers.ts(+9 -1)📝
packages/vinext/src/shims/server.ts(+57 -0)📝
tests/__snapshots__/entry-templates.test.ts.snap(+156 -84)📝
tests/app-page-cache.test.ts(+106 -0)📝
tests/app-page-render.test.ts(+2 -2)📝
tests/app-route-handler-cache.test.ts(+74 -0)📝
tests/app-route-handler-execution.test.ts(+56 -0)📝
tests/app-route-handler-runtime.test.ts(+166 -0)➕
tests/app-static-generation.test.ts(+47 -0)📝
tests/e2e/app-router/rsc-fetch-errors.spec.ts(+40 -41)➕
tests/fixtures/app-basic/app/rsc-fetch-redirect-src/page.tsx(+5 -0)📄 Description
What this changes
Fixes two App Router cache-safety issues around request-specific data:
dynamic = "force-static"anddynamic = "error"for route-handler request APIs by stubbing or throwing for directNextRequestfields andnext/headers.request.ipandrequest.geoaccess as dynamic in auto mode.Why
Route handlers could previously expose request-specific IP/geo/header/cookie data through untracked request fields, and HTML ISR could cache page output before lazy streamed Server Components had finished touching
cookies()orheaders(). Both cases could put per-request output into shared cache.Approach
This mirrors Next.js' static-generation request policy instead of treating dynamic API access as observation-only state:
force-staticroute handlers receive empty readonly stubs for request-specific APIs.dynamic = "error"throws when request-specific APIs are touched during static rendering.Next.js references
Checked against Next.js canary commit
ae61573e062e900050b8e6b24626e450accc4570:workStore.forceStaticfordynamic = "force-static"and proxy the request throughforceStaticRequestHandlers:github.com/vercel/next.js@ae61573e06/packages/next/src/server/route-modules/app-route/module.ts (L907-L913)request.headersandrequest.cookies:github.com/vercel/next.js@ae61573e06/packages/next/src/server/route-modules/app-route/module.ts (L1038-L1056)headers()underforceStaticreturnsHeadersAdapter.seal(new Headers({}))without tracking, whiledynamic = "error"throwsStaticGenBailoutError:github.com/vercel/next.js@ae61573e06/packages/next/src/server/request/headers.ts (L58-L101)cookies()underforceStaticreturns sealed empty request cookies, whiledynamic = "error"throwsStaticGenBailoutError:github.com/vercel/next.js@ae61573e06/packages/next/src/server/request/cookies.ts (L52-L62)github.com/vercel/next.js@ae61573e06/packages/next/src/server/web/spec-extension/adapters/request-cookies.ts (L36-L49)append,delete, andset:github.com/vercel/next.js@ae61573e06/packages/next/src/server/web/spec-extension/adapters/headers.ts (L117-L132)github.com/vercel/next.js@ae61573e06/packages/next/src/server/app-render/app-render.tsx (L7967-L7974)Validation
vp checkvp test run tests/app-route-handler-runtime.test.ts tests/app-route-handler-execution.test.ts tests/app-route-handler-cache.test.ts tests/app-route-handler-policy.test.ts tests/app-page-cache.test.ts tests/app-page-render.test.ts tests/app-page-response.test.ts tests/app-page-probe.test.ts tests/shims.test.tsvp test run tests/app-router.test.tsvp run vinext#buildRisks / follow-ups
The behavior is deliberately stricter around cacheable App Router work. The main compatibility risk is code that relied on reading real request fields under
dynamic = "force-static", which conflicts with Next.js' empty-stub behavior and can leak per-request data into shared cache.🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.