nextjs - ✅(Solved) Fix Stale cached page list on first client navigation after rewrite in Pages Router dev [1 pull requests, 1 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
vercel/next.js#91724Fetched 2026-04-08 01:07:13
View on GitHub
Comments
0
Participants
1
Timeline
4
Reactions
0
Author
Participants
Timeline (top)
labeled ×2cross-referenced ×1issue_type_added ×1

Fix Action

Fixed

PR fix notes

PR #91760: Fix stale dev page list during rewrite adoption

Description (problem / solution / changelog)

What?

Fix a Pages Router development bug where the client can keep rendering the previously loaded page after a rewrite resolves to a route that became available later.

This change:

  • lets PageLoader refresh the dev page list on demand
  • avoids reusing cached dev manifest state during an explicit refresh
  • retries rewrite resolution once when the rewritten target is missing from the current page list
  • adds a development regression that materializes the rewritten target during the test flow and verifies client-side navigation still adopts it correctly

Why?

This fixes a stale client page-list problem reported in #91724.

In the reported case:

  1. /docs/start is loaded first.
  2. The rewritten target page does not exist yet.
  3. The rewritten target is materialized afterward.
  4. A client-side navigation to /docs/example is rewritten to /docs/_handlers/example.
  5. The server can already serve the rewritten target.
  6. The client can still continue with stale page-list state and keep rendering the previously loaded page.

That leaves the client resolving the rewrite against stale route information instead of switching to the rewritten page immediately.

How?

PageLoader now supports an explicit dev page-list refresh that bypasses both the cached manifest and any existing dev-manifest fetch promise.

The router only does that refresh in the rewrite path, when the rewritten target is missing from the current client page list.

The regression test covers the same sequence in next dev by:

  • starting on /docs/start
  • materializing the rewritten target through an API route
  • navigating client-side through /docs/example
  • asserting that the rewritten route renders while the public URL stays the same
  • asserting that no dev redbox appears

Fixes #91724

Changed files

  • packages/next/src/client/page-loader.ts (modified, +25/-18)
  • packages/next/src/shared/lib/router/router.ts (modified, +6/-1)
  • test/development/pages-dir/stale-dev-pages-manifest/fixture/components/RewrittenRouteComponent.js (added, +3/-0)
  • test/development/pages-dir/stale-dev-pages-manifest/fixture/components/RouteRenderer.js (added, +23/-0)
  • test/development/pages-dir/stale-dev-pages-manifest/fixture/components/StartPageControls.js (added, +26/-0)
  • test/development/pages-dir/stale-dev-pages-manifest/fixture/page-sources/example-rewritten-page.js (added, +23/-0)
  • test/development/pages-dir/stale-dev-pages-manifest/fixture/pages/api/materialize-handler.js (added, +20/-0)
  • test/development/pages-dir/stale-dev-pages-manifest/fixture/pages/docs/[...slug].js (added, +54/-0)
  • test/development/pages-dir/stale-dev-pages-manifest/fixture/proxy.js (added, +48/-0)
  • test/development/pages-dir/stale-dev-pages-manifest/fixture/public/favicon.ico (added, +1/-0)
  • test/development/pages-dir/stale-dev-pages-manifest/index.test.ts (added, +47/-0)

Code Example

Operating System:
  Platform: darwin
  Arch: arm64
  Version: Darwin Kernel Version 25.3.0: Wed Jan 28 20:54:55 PST 2026; root:xnu-12377.91.3~2/RELEASE_ARM64_T6031
  Available memory (MB): 65536
  Available CPU cores: 16
Binaries:
  Node: 22.6.0
  npm: 10.8.2
  Yarn: 1.22.22
  pnpm: 10.30.2
Relevant Packages:
  next: 16.2.1-canary.2 // Latest available version is detected (16.2.1-canary.2).
  eslint-config-next: N/A
  react: 19.2.4
  react-dom: 19.2.4
  typescript: 5.9.3
Next.js Config:
  output: N/A
RAW_BUFFERClick to expand / collapse

Link to the code that reproduces this issue

https://github.com/gurkerl83/next-pages-client-stale-manifest-repro

To Reproduce

  1. Clone the reproduction repository.
  2. Install dependencies with pnpm install.
  3. Start the app in development with pnpm dev.
  4. Open /docs/start in the browser.
  5. Confirm the handler route is shown as missing.
  6. Click Materialize example.
  7. Click Go to example so the navigation happens client-side.
  8. Observe that the request is rewritten by proxy.ts from /docs/example to /docs/_handlers/example.
  9. Observe that the server can already serve /docs/_handlers/example, but the browser can still throw Expected component 'RewrittenOnlyComponent' to be defined.
  10. Hard-refresh /docs/example and observe that the page then renders correctly.

If you want to retry the exact first-hit scenario, click Reset handlers, restart pnpm dev, and open /docs/start again.

Current vs. Expected behavior

Following the steps above, I expect the client-side navigation to adopt the rewritten page component once the server can already serve the rewritten handler page.

Instead, on the first client-side navigation in development:

  • the browser starts from the catch-all page at /docs/start
  • the handler page /docs/_handlers/example is created afterward
  • proxy.ts rewrites the client-side /_next/data/... request for /docs/example to /docs/_handlers/example
  • the server can already serve the rewritten handler page and return the correct data
  • but the client can still keep rendering the previously loaded catch-all page component
  • the catch-all page then tries to render rewritten handler data and throws Expected component 'RewrittenOnlyComponent' to be defined

A hard refresh on /docs/example works, which suggests the rewritten handler route is valid on the server but the client-side route adoption is stale during the first rewritten data transition.

Provide environment information

Operating System:
  Platform: darwin
  Arch: arm64
  Version: Darwin Kernel Version 25.3.0: Wed Jan 28 20:54:55 PST 2026; root:xnu-12377.91.3~2/RELEASE_ARM64_T6031
  Available memory (MB): 65536
  Available CPU cores: 16
Binaries:
  Node: 22.6.0
  npm: 10.8.2
  Yarn: 1.22.22
  pnpm: 10.30.2
Relevant Packages:
  next: 16.2.1-canary.2 // Latest available version is detected (16.2.1-canary.2).
  eslint-config-next: N/A
  react: 19.2.4
  react-dom: 19.2.4
  typescript: 5.9.3
Next.js Config:
  output: N/A

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

Pages Router, Turbopack

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

next dev (local)

Additional context

This issue was discovered while building next-slug-splitter, which uses proxy.ts to create handler pages on demand during development instead of generating all routes upfront at startup.

The sequence that triggers the bug:

  1. Browser loads a catch-all page (e.g. /docs/start)
  2. A handler page (e.g. /docs/_handlers/example) is materialized after boot
  3. proxy.ts rewrites a client-side navigation to the new handler page
  4. Server returns the correct rewritten data
  5. Client still renders the old catch-all component — stale manifest

This blocks any tool that wants to offer lazy, on-demand route generation in dev mode via proxy-based rewrites.

The repro sets skipProxyUrlNormalize: true only so proxy.ts can observe the raw /_next/data/... request shape — it is not the suspected source of the bug.

Relevant client code:

  • next/dist/client/page-loader.js
  • next/dist/shared/lib/router/router.js

The repro also sets skipProxyUrlNormalize: true, but that is only there so proxy.ts can observe the raw client-side /_next/data/... request shape. It is not the suspected source of the bug.

extent analysis

Fix Plan

To resolve the issue of stale client-side page information during rewrite adoption in Pages Router development mode, we need to update the client-side routing logic to handle rewritten routes correctly.

Here are the steps to fix the issue:

  • Update next.config.js to include a custom rewrites function that handles client-side navigation.
  • Modify the proxy.ts file to correctly rewrite requests to the new handler page.
  • Update the client-side routing logic in next/dist/client/page-loader.js and next/dist/shared/lib/router/router.js to handle the rewritten routes.

Code Changes

// next.config.js
module.exports = {
  // ... other configurations ...
  rewrites: async () => {
    return [
      {
        source: '/docs/example',
        destination: '/docs/_handlers/example',
      },
    ];
  },
};
// proxy.ts
import { NextApiRequest, NextApiResponse } from 'next';

const proxy = (req: NextApiRequest, res: NextApiResponse) => {
  // ... other proxy logic ...
  if (req.url.startsWith('/_next/data')) {
    const rewrittenUrl = req.url.replace('/docs/example', '/docs/_handlers/example');
    return res.rewrite(rewrittenUrl);
  }
  // ... other proxy logic ...
};
// next/dist/client/page-loader.js
import { useRouter } from 'next/router';

const pageLoader = () => {
  const router = useRouter();
  // ... other page loading logic ...
  if (router.asPath.startsWith('/docs/example')) {
    router.replace('/docs/_handlers/example');
  }
  // ... other page loading logic ...
};

Verification

To verify that the fix worked, follow these steps:

  • Restart the development server with pnpm dev.
  • Open /docs/start in the browser.
  • Click Materialize example.
  • Click Go to example to trigger client-side navigation.
  • The page should now render correctly without throwing any errors.

Extra Tips

  • Make sure to update the next package to the latest version to ensure you have the latest fixes and features.
  • If you're using a custom rewrites function, ensure it's correctly handling client-side navigation.
  • Consider adding logging or debugging statements to help diagnose any issues that may arise during the rewrite adoption process.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

nextjs - ✅(Solved) Fix Stale cached page list on first client navigation after rewrite in Pages Router dev [1 pull requests, 1 participants]