AI & Agent Dev Bug Sandbox logo
AI & Agent Dev Bug Sandbox
Back to Radar

App Router: A <Link> Clicked While Its Prefetch Is In Flight Commits With No <Title> (And Can Commit An Empty Segment) — Pending Segment-Cache Entry Is Handed To React As A Plain Promise

When a navigation clicks a Link during an in-flight prefetch, a pending segment-cache entry is passed to React as a plain promise. In partial or rejected prefetches the promise resolves to null, causing React to commit an empty segment and drop the document title.

highConfidence 90%Next.jsAffected V16.2.11Affected V16.3.5Affected Vcanary

Origin Analysis

In createCacheNodeForSegment, EntryStatus.Pending entries are handled by storing waitForSegmentCacheEntry(...).then(...) promises directly as prefetchRsc and head. React's InnerLayoutRouter only unwraps DeferredRsc values, not plain promises. The pending entry is partial (isPartial: false) so the head is assigned from the promise; when it resolves to null, the title is wiped and the segment can commit empty.
1. Load /deal and wait for viewport prefetches to start.\n2. Click 'Open trip' (<Link href="/deal/trip">).\n3. Immediately click the 'Guests' tab (<Link href="/deal/trip/guests">) while the prefetches are still pending and the first navigation has not committed.\n4. Observe that /deal/trip/guests renders but document.title becomes empty and does not recover; in some cases the URL commits with an empty content slot.

Fixing Code Block

Edge Case Audit

Treating pending entries as a miss may trigger an extra server round-trip for the same prefetch, reducing prefetch effectiveness under high latency. Under rapid repeated navigation, duplicate requests could occur if the router does not deduplicate by URL. Rollback: revert the two null assignments and the partial flags to restore promise-based pending handling. Test across Next.js 16.2.x, 16.3.x, and canary with PPR both off and on; also add a Playwright test for the click-during-prefetch race.

Ecosystem Topology