Problem
When a navigation is superseded (rapid clicks) after body.tee() but before the success path, the cache-branch arrayBuffer() read is abandoned. If that read rejects (stream error from an aborted/failed underlying response), it surfaces as an unhandled promise rejection — console noise in dev and a potential 'unhandledrejection' event firing AppRouterRedirectBridge's window listener on unrelated errors.
Evidence
packages/vinext/src/server/app-browser-entry.ts:2018 — cacheBufferPromise = new Response(cacheBranch).arrayBuffer() is created from the tee'd cache branch but only awaited/caught on the success path (lines 2058, 2061).
packages/vinext/src/server/app-browser-entry.ts:2046 — Early returns on non-committed outcome (line 2046) and on stale navId (line 2049) abandon cacheBufferPromise with no .catch(); if the tee'd cache branch errors (e.g. the reactBranch/underlying body fails), the arrayBuffer() read rejects with no handler.
Next.js behavior (Next.js handles this correctly — vinext-only bug)
The vinext bug is that it creates a standalone cacheBufferPromise = new Response(cacheBranch).arrayBuffer() (app-browser-entry.ts:2018) from a tee'd branch, then on superseded-navigation early returns (lines 2020, 2026, 2046, 2049) abandons it with no .catch(), so a stream error surfaces as an unhandled rejection. Next.js's corresponding navigation fetch (fetch-server-response.ts) tees the body into responseBodyClone only when experimental cached-navigations is on (processFetch :393-396), but it always consumes that clone via res.cacheData inside Promise.all([flightResponsePromise, res.cacheData]) (:260-263), and the entire body is wrapped in try/catch (:169/:307) that falls back to MPA navigation on any rejection — there is no code path that creates the clone-read promise and then early-returns past it without awaiting or catching. The segment-cache prefetch path (cache.ts:2212-2219) is identically structured: the cache branch is awaited in a Promise.all inside a try/catch (:2283). Navigation supersession in Next.js is handled via AbortSignals and the router/segment-cache scheduler rather than by abandoning a dangling buffer-read promise mid-function (grep for navId/isCurrentNavigation/superseded in fetch-server-response.ts returns nothing). Additionally, Next.js's unhandledrejection listener guards on isRedirectError (app-router.tsx:249) so it would not misfire on an unrelated stream error even hypothetically. Thus the structural defect — an uncaught, abandoned tee-branch read promise on superseded navigation — is vinext-specific and does not exist in Next.js.
Citations: .nextjs-ref/packages/next/src/client/components/router-reducer/fetch-server-response.ts:169 (try start), :393-396 (tee creating responseBodyClone cache branch), :260-263 (Promise.all awaits flightResponsePromise AND res.cacheData together), :307-341 (catch -> MPA fallback); resolveStaticStageData at :431-465 consumes/cancels the clone; segment-cache counterpart at .nextjs-ref/packages/next/src/client/components/segment-cache/cache.ts:2212-2219 (Promise.all over decoded stream + response.cacheData) inside try at :2283 catch; AppRouterRedirectBridge analogue at .nextjs-ref/packages/next/src/clie
Suggested fix
Attach void cacheBufferPromise.catch(() => {}) immediately after creating it (or in the two early-return branches at lines 2046 and 2049) so a superseded navigation never leaves the cache-branch read unhandled.
Test plan
Unit: superseded navigation whose tee'd stream errors emits no unhandledrejection.
Related / notes
Attach a no-op catch at creation (app-browser-entry.ts:2018). BLOCKED on PR #1962 (same file).
Found via a deep source audit of main @ fd10233 (2026-06-12). Behavior parity-checked against Next.js v16.3.0-canary.7 source; citations above reference packages/next/src/... in the Next.js repo. Screened against all open issues/PRs as of 2026-06-12 to avoid duplicating tracked work.
Problem
When a navigation is superseded (rapid clicks) after body.tee() but before the success path, the cache-branch arrayBuffer() read is abandoned. If that read rejects (stream error from an aborted/failed underlying response), it surfaces as an unhandled promise rejection — console noise in dev and a potential 'unhandledrejection' event firing AppRouterRedirectBridge's window listener on unrelated errors.
Evidence
packages/vinext/src/server/app-browser-entry.ts:2018— cacheBufferPromise = new Response(cacheBranch).arrayBuffer() is created from the tee'd cache branch but only awaited/caught on the success path (lines 2058, 2061).packages/vinext/src/server/app-browser-entry.ts:2046— Early returns on non-committed outcome (line 2046) and on stale navId (line 2049) abandon cacheBufferPromise with no .catch(); if the tee'd cache branch errors (e.g. the reactBranch/underlying body fails), the arrayBuffer() read rejects with no handler.Next.js behavior (Next.js handles this correctly — vinext-only bug)
The vinext bug is that it creates a standalone cacheBufferPromise = new Response(cacheBranch).arrayBuffer() (app-browser-entry.ts:2018) from a tee'd branch, then on superseded-navigation early returns (lines 2020, 2026, 2046, 2049) abandons it with no .catch(), so a stream error surfaces as an unhandled rejection. Next.js's corresponding navigation fetch (fetch-server-response.ts) tees the body into responseBodyClone only when experimental cached-navigations is on (processFetch :393-396), but it always consumes that clone via res.cacheData inside Promise.all([flightResponsePromise, res.cacheData]) (:260-263), and the entire body is wrapped in try/catch (:169/:307) that falls back to MPA navigation on any rejection — there is no code path that creates the clone-read promise and then early-returns past it without awaiting or catching. The segment-cache prefetch path (cache.ts:2212-2219) is identically structured: the cache branch is awaited in a Promise.all inside a try/catch (:2283). Navigation supersession in Next.js is handled via AbortSignals and the router/segment-cache scheduler rather than by abandoning a dangling buffer-read promise mid-function (grep for navId/isCurrentNavigation/superseded in fetch-server-response.ts returns nothing). Additionally, Next.js's unhandledrejection listener guards on isRedirectError (app-router.tsx:249) so it would not misfire on an unrelated stream error even hypothetically. Thus the structural defect — an uncaught, abandoned tee-branch read promise on superseded navigation — is vinext-specific and does not exist in Next.js.
Citations: .nextjs-ref/packages/next/src/client/components/router-reducer/fetch-server-response.ts:169 (try start), :393-396 (tee creating responseBodyClone cache branch), :260-263 (Promise.all awaits flightResponsePromise AND res.cacheData together), :307-341 (catch -> MPA fallback); resolveStaticStageData at :431-465 consumes/cancels the clone; segment-cache counterpart at .nextjs-ref/packages/next/src/client/components/segment-cache/cache.ts:2212-2219 (Promise.all over decoded stream + response.cacheData) inside try at :2283 catch; AppRouterRedirectBridge analogue at .nextjs-ref/packages/next/src/clie
Suggested fix
Attach
void cacheBufferPromise.catch(() => {})immediately after creating it (or in the two early-return branches at lines 2046 and 2049) so a superseded navigation never leaves the cache-branch read unhandled.Test plan
Unit: superseded navigation whose tee'd stream errors emits no unhandledrejection.
Related / notes
Attach a no-op catch at creation (app-browser-entry.ts:2018). BLOCKED on PR #1962 (same file).
Found via a deep source audit of
main@ fd10233 (2026-06-12). Behavior parity-checked against Next.js v16.3.0-canary.7 source; citations above referencepackages/next/src/...in the Next.js repo. Screened against all open issues/PRs as of 2026-06-12 to avoid duplicating tracked work.