From 567d6050587a117c53bdc6d4981a082e85fe0b71 Mon Sep 17 00:00:00 2001 From: Zack Tanner <1939140+ztanner@users.noreply.github.com> Date: Sat, 31 Jan 2026 07:52:59 -0800 Subject: [PATCH] add handling to skip prefetch payloads if partial --- .../components/router-reducer/ppr-navigations.ts | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/packages/next/src/client/components/router-reducer/ppr-navigations.ts b/packages/next/src/client/components/router-reducer/ppr-navigations.ts index 5c38be4532502..f425d7f4e2682 100644 --- a/packages/next/src/client/components/router-reducer/ppr-navigations.ts +++ b/packages/next/src/client/components/router-reducer/ppr-navigations.ts @@ -1073,6 +1073,14 @@ function createCacheNodeForSegment( doesSegmentNeedDynamicRequest = isCachedRscPartial } + if (isCachedRscPartial) { + // Partial prefetch payloads may include unresolved thenables that never + // resolve during prefetch. We must not render them as initial UI, or a + // Suspense boundary can remain stuck in its fallback indefinitely. Only + // the dynamic response should fulfill missing data. + prefetchRsc = null + } + // If this is a page segment, we need to do the same for the head. This // follows analogous logic to the segment data above. // TODO: We don't need to store the head on the page segment's CacheNode; we @@ -1082,10 +1090,10 @@ function createCacheNodeForSegment( let prefetchHead: HeadData | null = null let head: React.ReactNode | null = null let doesHeadNeedDynamicRequest: boolean = isPage + let isCachedHeadPartial: boolean = true if (isPage) { let cachedHead: HeadData | null = null - let isCachedHeadPartial: boolean = true if (metadataVaryPath !== null) { const metadataEntry = readSegmentCacheEntry(now, metadataVaryPath) if (metadataEntry !== null) { @@ -1154,6 +1162,12 @@ function createCacheNodeForSegment( } } + if (isPage && isCachedHeadPartial) { + // Same rationale as prefetchRsc: avoid rendering partial head data that may + // contain unresolved thenables. + prefetchHead = null + } + // Now that we're creating a new segment, write its data to the BFCache. A // subsequent back/forward navigation will reuse this same data, until or // unless it's cleared by a refresh/revalidation.