vercel / vercel/next.js

Segment cache silently drops navigations when the RSC payload fetch stalls or fails (can also commit a stale canonical URL)

Open
#97,807 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
JavaScript
Stars
142k
Forks
32.5k
Avg merge
2d 14h
Merged PRs (30d)
351

Description

Link to the code that reproduces this issue

https://github.com/jdiaz-tls/next-swallowed-navigation-repro

To Reproduce
  1. npm install && npm run build && npx serve out -l 3000 (app uses output: "export")
  2. Open http://localhost:3000/projects?id=1&tab=estimate (full page load)
  3. Simulate a stalled/broken connection for router payload fetches — either DevTools → Network request blocking for pattern *__next*, or paste in the console:
    const orig = window.fetch;
    window.fetch = (u, ...a) => {
      const s = String(u instanceof Request ? u.url : u);
      return s.includes("__next") || /\.txt(\?|$)/.test(s)
        ? new Promise(() => {})   // hang forever (use Promise.reject(new TypeError("Failed to fetch")) for the rejection variant — same result)
        : orig(u, ...a);
    };
    
  4. Click All Projects
Current vs. Expected behavior

Current: nothing happens. The URL stays /projects?id=1&tab=estimate, the page doesn't change, and nothing is logged. The click is permanently lost, and so is every retry. The cause appears to be that the navigation promise failure is swallowed (navigateToUnknownRoute(...).catch(() => state) in segment-cache/navigation.js; the same "If the navigation fails, return the current state" pattern is present in 16.3.2 and in 16.4.0-canary.4, where it now lives in client/components/app-router-state.js). A rejecting fetch behaves the same as a hanging one — unlike the older router-reducer path, which logged "Failed to fetch RSC payload … Falling back to browser navigation" and performed an MPA navigation.

In our production app (static export on Cloudflare Pages) we additionally observed a second symptom under the same conditions: with a cached route for the pathname /projects that was rendered with ?id=X&tab=Y, clicking a link to bare /projects from another page committed the old canonical URL — the address bar changed to /projects?id=X&tab=Y and the stale page rendered, i.e. the user was navigated "back into" a record they were trying to leave.

Expected: on payload fetch failure, fall back to a full-document navigation (like the pre-segment-cache router did), or at minimum surface an error. A navigation should also never commit search params the user didn't navigate to.

experimental.optimisticRouting: true does not change the outcome.

Provide environment information
Operating System:
  Platform: win32
  Arch: x64
  Version: Windows 11 Pro
  Available memory (MB): 32070
  Available CPU cores: 22
Binaries:
  Node: 24.15.0
  npm: 11.12.1
Relevant Packages:
  next: 16.2.6 (also verified against 16.3.2 and 16.4.0-canary.4 dist output)
  react: 19.2.8
  react-dom: 19.2.8
Next.js Config:
  output: export
Which area(s) are affected? (Select all that apply)

Navigation

Which stage(s) are affected? (Select all that apply)

next build (local), Other (deployed static export)

Additional context

First noticed as a real-user report on a production static-export app served by Cloudflare Pages over a flaky connection: "All Projects won't go back" and "clicking Projects takes me straight into the project I was in before". Both symptoms reproduce deterministically with the fetch patch above.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with segment-cache/navigation.js and client/components/app-router-state.js, especially the navigation-failure handling described in the issue, then run the linked reproduction with the RSC fetch stalled or rejected. Done means a failed payload fetch produces a full-document fallback or visible error, and navigation does not commit stale search parameters.

Written by the indexing model from the issue text.

Assessment

Tech stack
javascript, next.js
Domain
frontend
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
52/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.