Skip to content

fix(pages): render custom errors for notFound results - #1737

Merged
james-elicx merged 4 commits into
cloudflare:mainfrom
NathanDrake2406:nathan/fix-not-found-req-url
Jun 5, 2026
Merged

fix(pages): render custom errors for notFound results#1737
james-elicx merged 4 commits into
cloudflare:mainfrom
NathanDrake2406:nathan/fix-not-found-req-url

Conversation

@NathanDrake2406

Copy link
Copy Markdown
Contributor

Overview

Area Details
Goal Match Next.js when a Pages Router data method returns notFound and the HTML request must render the configured 404/error page.
Core change resolvePagesPageData() now returns an HTML notFound signal instead of constructing the built-in 404 response directly.
Main boundary The generated Pages entry owns rerouting to pages/404 or pages/_error, while data requests still return the JSON-shaped 404 envelope.
Primary files pages-page-data.ts, pages-server-entry.ts, pages-get-initial-props.ts, dev-server.ts, tests/pages-router.test.ts.
Expected impact _error.getInitialProps(ctx) receives the original request URL and asPath for getStaticProps or getServerSideProps notFound results.

Why

A Pages Router notFound result is not the final HTML response. In Next.js, getStaticProps marks render metadata as not found, the Pages route handler delegates to render404(), and the server then resolves pages/404 before falling back to pages/_error. That fallback render still builds the normal NextPageContext, including ctx.req, ctx.res, and ctx.asPath.

Area Principle / invariant What this PR changes
HTML notFound Data resolution should describe the route outcome, not preempt the configured error-page renderer. HTML notFound returns { kind: "notFound" }; only /_next/data requests keep returning {} with status 404.
Error route rendering pages/404 and pages/_error should be resolved by the Pages entry with the original visible URL. The generated entry rerenders the configured not-found route with statusCode: 404 and the original asPath.
getInitialProps context Pages getInitialProps belongs at the page render boundary and should observe sent-response short-circuits. A typed helper invokes page getInitialProps in prod and dev without widening production code through any or broad assertions.

What changed

Scenario Before After
getStaticProps returns { notFound: true } for an HTML request vinext returned the built-in default 404, skipping custom pages/_error. vinext rerenders pages/404 or pages/_error and preserves 404 status.
_error.getInitialProps(ctx) on that rerender Not called, so ctx.req?.url and ctx.asPath never reached the page. Called with req.url and asPath from the original request, matching the upstream fixture.
/_next/data/...json not found Returned JSON-shaped 404. Preserved.
Maintainer review path
  1. packages/vinext/src/server/pages-page-data.ts - the resolver now emits a typed notFound signal for HTML while preserving JSON data-request behavior.
  2. packages/vinext/src/entries/pages-server-entry.ts - the generated Pages runtime reroutes that signal to explicit /404 or /_error, avoiding catch-all matches and recursion.
  3. packages/vinext/src/server/pages-get-initial-props.ts - shared typed loader for Pages component getInitialProps, including the sent-response exception from Next.js loadGetInitialProps.
  4. packages/vinext/src/server/dev-server.ts - dev parity for page and error-page getInitialProps context.
  5. tests/pages-router.test.ts and tests/pages-page-data.test.ts - upstream fixture port plus lower-boundary contract coverage.
Validation
  • vp check
  • vp test run tests/pages-page-data.test.ts
  • vp test run tests/pages-router.test.ts
  • Commit hook: vp test run tests/entry-templates.test.ts
  • Commit hook: checked formatting, lint, types, and knip
  • Upstream deploy suite: vp env exec --node 24 ./scripts/run-nextjs-deploy-suite.sh /Users/nathan/Projects/vinext/.refs/nextjs-v16.2.6 --retries 0 -c 1 --debug test/e2e/error-handler-not-found-req-url/error-handler-not-found-req-url.test.ts
Risk / compatibility
  • Public API: no new public API. The new helper is internal.
  • Runtime: affects Pages Router HTML notFound handling and Pages component getInitialProps invocation when no gSP/gSSP owns props.
  • Data requests: preserved as JSON 404 envelopes so client-router data fetches can still parse the response.
  • Compatibility: intentionally follows Next.js routing order for notFound fallback to pages/404 and pages/_error.
  • Existing-app risk: apps that relied on vinext's built-in 404 shortcut for gSP/gSSP notFound will now see their configured error page, which is the Next.js-compatible behavior.

References

Reference Why it matters
Next.js upstream test: error-handler-not-found-req-url The fixture this PR ports and passes through the vinext deploy harness.
Next.js getStaticProps notFound metadata Shows notFound becoming render metadata instead of an immediate built-in response.
Next.js render returns null for metadata.isNotFound Explains why the Pages handler owns the final 404 render decision.
Next.js Pages handler delegates isNotFound to render404() The production behavior vinext now mirrors.
Next.js render404 and error fallback Shows the /404 then /_error fallback sequence.
Next.js context passed to loadGetInitialProps Confirms ctx.req, ctx.res, and ctx.asPath are part of the error render context.
Next.js loadGetInitialProps The sent-response and invalid-return semantics used by the vinext helper.
Next.js docs for getStaticProps.notFound Documents that notFound should render a 404 page.

Pages getStaticProps and getServerSideProps notFound HTML results returned the built-in 404 response directly. That skipped the configured pages/404 or pages/_error render path, so _error.getInitialProps never received ctx.req.url or ctx.asPath for the original request.

The page-data resolver now returns a typed notFound signal for HTML requests while preserving JSON-shaped 404 data responses. The generated Pages entry rerenders the configured not-found route with the original asPath, and Pages getInitialProps is loaded through a shared typed helper for prod and dev parity.
@pkg-pr-new

pkg-pr-new Bot commented Jun 4, 2026

Copy link
Copy Markdown

Open in StackBlitz

npm i https://pkg.pr.new/vinext@1737

commit: 81badc9

…r context, and response-sent handling

- Call getInitialProps with component as this receiver
- Thread caught errors through to _error.getInitialProps(ctx.err)
- Check headersSent || writableEnded in dev server after getInitialProps
- Add tests: gSSP notFound, explicit 404, data JSON 404, err on throw, this binding
@NathanDrake2406
NathanDrake2406 marked this pull request as ready for review June 4, 2026 15:50
@james-elicx

Copy link
Copy Markdown
Member

/bigbonk review

@ask-bonk ask-bonk Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review: render custom errors for notFound results

Solid, well-scoped change that brings Pages Router notFound handling closer to Next.js. The core design — having resolvePagesPageData() emit a typed notFound signal for HTML while preserving the JSON 404 envelope for /_next/data requests, and letting the generated entry own the /404 -> /_error fallback — matches the upstream render404() flow. The recursion guard (routePattern !== "/404" && routePattern !== "/_error") correctly prevents infinite loops, and err is forwarded only on the SSR-throw path (not the notFound path), which is the right distinction.

I ran the targeted suites locally and all pass:

  • vp test run tests/pages-page-data.test.ts (23 passed)
  • vp test run tests/pages-router.test.ts (new notFound + gssp-throw tests pass)
  • vp test run tests/entry-templates.test.ts (24 passed)
  • vp check on the changed server files (clean)

A few non-blocking observations below — none of them block merge.

Observations

1. _app.getInitialProps interaction (pre-existing gap, not introduced here). The new block calls the page component's getInitialProps directly, regardless of whether a custom _app defines getInitialProps. In Next.js, when _app has getInitialProps, the App's gIP owns calling the page's gIP (loadGetInitialProps(ctx.Component, ctx.ctx)) and wraps the result as { pageProps }. vinext doesn't appear to invoke App.getInitialProps anywhere today, so this PR doesn't regress that — it improves the common (no custom App gIP) case. Worth a tracking issue if not already filed.

2. Stricter-than-Next.js return validation. The helper rejects non-plain-object returns (arrays, functions) via isPropsObject, whereas Next.js loadGetInitialProps only rejects falsy values (if (!props)). This is arguably better, but it is a deliberate divergence from upstream — flagging in case strict parity is preferred here.

3. Minor: response-sent check asymmetry. The prod block in pages-page-data.ts checks only res.headersSent while the dev block and the helper check headersSent || writableEnded. This is correct in practice because the prod PagesReqResResponse backs headersSent with its ended flag (so res.end() flips it), but the inline check reads slightly inconsistently next to the helper. See inline comment.

Nice test coverage — the upstream fixture port plus the lower-boundary pages-page-data contract tests give good confidence.

defaultLocale: options.i18n.defaultLocale,
});

if (res.headersSent) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor: the helper's isResponseSent checks headersSent || writableEnded, and the dev-server block checks both, but here only res.headersSent is checked. It's correct for the prod PagesReqResResponse (its headersSent getter is backed by the ended flag set in end()), so there's no actual bug — but the asymmetry reads oddly next to the helper. Consider relying on the helper's own sent-detection or mirroring the dev check for consistency.

@ask-bonk

ask-bonk Bot commented Jun 4, 2026

Copy link
Copy Markdown
Contributor

Review posted successfully to PR #1737.

Summary

I reviewed PR #1737 (fix(pages): render custom errors for notFound results) and posted a review with one inline comment and three non-blocking observations.

Verdict: Solid, well-scoped change. No blocking issues found.

What's good:

  • The core design (typed notFound signal for HTML, JSON 404 envelope preserved for /_next/data, generated entry owns the /404/_error fallback) correctly mirrors Next.js's render404() flow.
  • Recursion guard (routePattern !== "/404" && routePattern !== "/_error") correctly prevents infinite loops.
  • err is forwarded only on the SSR-throw path, not the notFound path — the right distinction.
  • req.url/asPath correctly flow through to _error.getInitialProps via the recursion passing the original url.
  • Dev/prod parity is maintained.

Verification performed locally (all pass):

  • tests/pages-page-data.test.ts (23 passed)
  • tests/pages-router.test.ts notFound + gssp-throw tests
  • tests/entry-templates.test.ts (24 passed)
  • vp check on changed server files (clean)

Non-blocking observations raised:

  1. _app.getInitialProps isn't invoked (pre-existing vinext gap, not a regression — this PR improves the common case).
  2. The helper rejects non-plain-object returns (arrays/functions) where Next.js only rejects falsy — a deliberate stricter divergence worth flagging.
  3. Minor response-sent check asymmetry in the prod block (headersSent only vs. helper's headersSent || writableEnded) — correct in practice, slightly inconsistent to read (inline comment).

github run

…r sent-check consistency

The prod block in resolvePagesPageData checked only res.headersSent, while
the helper's isResponseSent and the dev server check both headersSent and
writableEnded. The prod PagesReqResResponse only declares headersSent (its
getter is backed by the ended flag), so this is functionally correct in
prod, but the asymmetry is hard to read next to the helper and a future
change to the prod response shape would silently break sent-detection.

Export isResponseSent from pages-get-initial-props and use it at both
gSSP and gIP call sites so the prod resolver reuses the same
sent-detection logic as the helper.

Also adds tests for the writableEnded-only path and a focused unit test
for isResponseSent covering both prod-shaped and node-shaped res mocks.
@NathanDrake2406

Copy link
Copy Markdown
Contributor Author

Thanks for the review! Addressing the three observations:

1. _app.getInitialProps not invoked (pre-existing gap) — no change in this PR

Confirmed not introduced by this PR. Searching for loadGetInitialProps and App gIP usage in packages/vinext/src/server/:

  • dev-server.ts and prod-server.ts only call loadPagesGetInitialProps on the page component, never on App.
  • The generated pages-server-entry.ts _renderPage invokes loadPagesGetInitialProps(options.pageModule.default, ...) (the page module), not the App wrapper.
  • _app.tsx is wrapped around the page element in the React tree, but vinext doesn't extract a getInitialProps static from it.

This is the pre-existing behavior — the page gIP path works, the App gIP path is a known gap unrelated to notFound handling. I agree a tracking issue is worth filing (will do separately) but fixing it here would expand the PR's scope significantly (requires App gIP loading + { pageProps } wrapping in both dev/prod). Out of scope for this fix.

2. Stricter-than-Next.js return validation (deliberate divergence) — no change

The isPropsObject rejection of arrays/functions/primitives in pages-get-initial-props.ts:79-87 is intentional defense-in-depth. Next.js's if (!props) check accepts [] (a truthy array) which then crashes later when downstream code does Object.assign(pageProps, initialProps) or JSON.stringify over the page data. The stricter check throws early with a clear error message that names the offending component and value. Keeping this as a deliberate vinext improvement.

3. Response-sent check asymmetry — fixed

Implemented in a595ea8. Exported isResponseSent from pages-get-initial-props.ts and replaced both if (res.headersSent) checks in pages-page-data.ts (gSSP at line 487, gIP at line 697) with if (isResponseSent(res)). The prod PagesReqResResponse type only declares headersSent (its getter is backed by the ended flag in pages-node-compat.ts:203-204), so the prod-only inline check was functionally correct — but using the helper future-proofs the prod resolver against response-shape changes and unifies sent-detection with the dev path and the helper itself.

Added tests:

  • short-circuits getServerSideProps responses when only writableEnded is set
  • short-circuits getInitialProps responses when only writableEnded is set
  • Focused unit test for the exported isResponseSent covering both prod-shaped ({ headersSent }) and node-shaped ({ writableEnded }) mocks, plus the undefined/null edge cases.

@james-elicx

Copy link
Copy Markdown
Member

/bigbonk review

@ask-bonk ask-bonk Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review: render custom errors for notFound results

Well-scoped, correct change. I re-ran the targeted suites locally and everything passes:

  • tests/pages-page-data.test.ts — 26 passed
  • tests/pages-router.test.ts (the three new notFound + gssp-throw tests) — passed
  • tests/entry-templates.test.ts — 24 passed
  • vp check on the three changed server files — clean

The core design matches Next.js's render404() flow: resolvePagesPageData() emits a typed notFound signal for HTML while preserving the JSON 404 envelope for /_next/data, and the generated entry owns the /404/_error fallback. I verified against upstream loadGetInitialProps (packages/next/src/shared/lib/utils.ts) — the this-binding, the sent-response short-circuit, and the asPath/req.url propagation all line up. The recursion guard (routePattern !== "/404" && routePattern !== "/_error") is correct, err is forwarded only on the SSR-throw path (not the notFound recursion), and __findPagesNotFoundRoute() is strictly better than the old matchRoute("/404") since it can't accidentally match a catch-all.

The three follow-ups from the prior review are resolved appropriately (the isResponseSent unification is a nice future-proofing). One new non-blocking perf observation below.

Non-blocking observations

1. createGsspReqRes() now runs on every static page without gSP/gSSP, even those with no getInitialProps. See inline comment — the req/res pair (header iteration + an unresolved responsePromise) is allocated per request on the static-page hot path, then thrown away because loadPagesGetInitialProps returns null early when there's no gIP. Worth gating behind a cheap gIP-presence check.

2. Sent-response branch diverges slightly from upstream. Next.js's loadGetInitialProps returns props unchanged when isResSent(res) is true (even if falsy/non-object). The helper normalizes non-objects to {} in that branch (pages-get-initial-props.ts:76). This is defensible (the caller spreads the result into pageProps, so a non-object would crash), just flagging the intentional difference.

3. Missing the dev-only instance-method guard. Upstream loadGetInitialProps throws in dev if getInitialProps is defined as a prototype/instance method (App.prototype?.getInitialProps). The helper omits this. Minor dev-ergonomics gap, not worth holding the PR.

Nice test coverage — the upstream fixture port plus the lower-boundary pages-page-data contract tests give good confidence.

typeof options.pageModule.getServerSideProps !== "function" &&
typeof options.pageModule.getStaticProps !== "function"
) {
const { req, res, responsePromise } = options.createGsspReqRes();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

createGsspReqRes() is invoked unconditionally for every static page that lacks getServerSideProps/getStaticProps — i.e. the common case of a plain static page with no getInitialProps either. createPagesReqRes iterates request headers, allocates the req/res shims, and creates an unresolved responsePromise (pages-node-compat.ts:128-194), all of which is discarded the moment loadPagesGetInitialProps returns null because there's no gIP function.

Consider checking for a getInitialProps function before building the req/res. That keeps the hot path for ordinary static pages allocation-free and avoids leaving a dangling unresolved promise per request. For example, export a small hasPagesGetInitialProps(component) (or reuse the existing private getInitialPropsFn) from pages-get-initial-props.ts and gate on it:

Suggested change
const { req, res, responsePromise } = options.createGsspReqRes();
if (
typeof options.pageModule.getServerSideProps !== "function" &&
typeof options.pageModule.getStaticProps !== "function" &&
hasPagesGetInitialProps(options.pageModule.default)
) {
const { req, res, responsePromise } = options.createGsspReqRes();

(The same applies to the dev-server block at dev-server.ts:1057 and the renderErrorPage call at dev-server.ts:1510, though those are less hot.)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in 81badc9. Exported hasPagesGetInitialProps from pages-get-initial-props.ts and gated the prod block on it. The hot path for plain static pages (no gSSP, no gSP, no gIP) is now allocation-free.

@ask-bonk

ask-bonk Bot commented Jun 5, 2026

Copy link
Copy Markdown
Contributor

Review posted successfully to PR #1737.

Summary

I reviewed PR #1737 (fix(pages): render custom errors for notFound results) and posted a COMMENT review with one inline suggestion and three non-blocking observations.

Verdict: Solid, correct, well-scoped change. No blocking issues.

Verification performed locally (all pass):

  • tests/pages-page-data.test.ts — 26 passed
  • tests/pages-router.test.ts — 3 new notFound + gssp-throw tests passed
  • tests/entry-templates.test.ts — 24 passed
  • vp check on the 3 changed server files — clean

What I confirmed against upstream Next.js (loadGetInitialProps in packages/next/src/shared/lib/utils.ts):

  • this-binding via getInitialProps.call(component, ctx) matches upstream
  • Sent-response short-circuit semantics line up
  • req.url/asPath propagation through the notFound recursion is correct
  • err is forwarded only on the SSR-throw path, not the notFound path
  • __findPagesNotFoundRoute() is strictly safer than the old matchRoute("/404") (can't match a catch-all)
  • Recursion guard prevents infinite loops

New observation raised (inline, non-blocking):

  1. createGsspReqRes() is now called unconditionally on every static page without gSP/gSSP — including the common case of no getInitialProps — allocating a req/res pair and an unresolved responsePromise that's immediately discarded. Suggested gating behind a cheap gIP-presence check (also applies to two dev-server call sites).
  2. Sent-response branch normalizes non-objects to {}, a defensible divergence from upstream's "return props unchanged".
  3. Helper omits upstream's dev-only prototype/instance-method getInitialProps guard — minor.

The three prior-review follow-ups were resolved appropriately.

github run

…check

The getInitialProps prod block in resolvePagesPageData unconditionally
called createGsspReqRes() for every static page without gSP/gSSP, even
when the page had no getInitialProps either. This allocated a req/res
pair and an unresolved responsePromise that was immediately discarded.

Export hasPagesGetInitialProps from pages-get-initial-props.ts and gate
the prod block on it, keeping the hot path for plain static pages
allocation-free.
@NathanDrake2406

Copy link
Copy Markdown
Contributor Author

Addressed the three observations from the latest review:

1. createGsspReqRes() allocation gating — fixed in 81badc98. Exported hasPagesGetInitialProps from pages-get-initial-props.ts and gated the prod block in resolvePagesPageData on it. The hot path for plain static pages (no gSSP, no gSP, no gIP) is now allocation-free — createGsspReqRes() is only called when there is actually a getInitialProps function present.

2. Sent-response normalizes non-objects to {} — no change. This is a deliberate, documented divergence from Next.js behavior. The caller spreads the result into pageProps, so a non-object return would crash — normalizing to {} avoids that crash and gives a clearer error path.

3. Missing dev-only instance-method guard — no change. Minor dev-ergonomics improvement beyond the scope of this PR.

@james-elicx

Copy link
Copy Markdown
Member

/bigbonk review

@ask-bonk ask-bonk Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-review: render custom errors for notFound results

Verified the latest revision (81badc98). This is a clean, well-scoped change and the three prior-review follow-ups are resolved appropriately. No blocking issues.

Verification (all green locally):

  • vp test run tests/pages-page-data.test.ts — 26 passed
  • vp test run tests/pages-router.test.ts — the 3 new notFound + gssp-throw integration tests pass (_error.getInitialProps reqUrl/asPath, explicit /404 over /_error, gSSP-throw err propagation)
  • vp test run tests/entry-templates.test.ts — 24 passed
  • vp check on the 3 changed server files — clean (format, lint, types)

What I confirmed:

  • Core design mirrors Next.js render404(): resolvePagesPageData() emits a typed notFound signal for HTML, JSON 404 envelope preserved for /_next/data, and the generated entry owns the /404/_error fallback.
  • __findPagesNotFoundRoute() is strictly safer than the old matchRoute("/404") (can't match a catch-all), and the recursion guard (routePattern !== "/404" && routePattern !== "/_error") prevents infinite loops on a custom 404/_error page that itself returns notFound.
  • err is forwarded only on the SSR-throw path (entry L1048), not on the notFound recursion (L833) — correct distinction.
  • req.url/asPath flow into _error.getInitialProps via the recursion's __forcedRoute + routeUrl.
  • The new hasPagesGetInitialProps gate (pages-page-data.ts:687) keeps the plain-static-page hot path allocation-free, addressing the prior perf observation.
  • loadPagesGetInitialProps this-binding (getInitialProps.call(component, context)) and sent-response short-circuit match upstream loadGetInitialProps.
  • prod-server.ts delegates Pages rendering to the built entry, so it inherits the new logic — no separate parity update needed.

One observation that's worth a note (non-blocking):

This PR newly invokes page-component getInitialProps in the prod resolver — before this change, resolvePagesPageData() never called page-level gIP at all, so a page exporting only getInitialProps (no gSP/gSSP) was previously SSR-rendered in prod without its initial props. The new behavior is the Next.js-correct one (gIP runs server-side on initial render), and it's well-tested. But the PR description frames the change as primarily about notFound/_error; this broader prod gIP enablement is a meaningful behavioral change that existing apps relying on client-only gIP fallback could notice. Worth calling out explicitly in the changelog/PR summary so it isn't a surprise.

See the one inline note below on dev/prod gating symmetry.

if (
typeof pageModule.getServerSideProps !== "function" &&
typeof pageModule.getStaticProps !== "function"
) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor symmetry note (non-blocking): the prod resolver now gates the gIP block on hasPagesGetInitialProps(...) (pages-page-data.ts:687), but this dev block only checks the absence of gSP/gSSP and relies on loadPagesGetInitialProps returning null early. Functionally fine in dev (no createGsspReqRes allocation here), but adding the same hasPagesGetInitialProps(PageComponent) guard would keep dev/prod reading identically and make the intent obvious. Up to you.

@ask-bonk

ask-bonk Bot commented Jun 5, 2026

Copy link
Copy Markdown
Contributor

Review posted successfully to PR #1737.

Summary

Re-reviewed PR #1737 (fix(pages): render custom errors for notFound results) at commit 81badc98 and posted a COMMENT review with one non-blocking inline note.

Verdict: Clean, correct, well-scoped change. No blocking issues. All three prior-review follow-ups were resolved appropriately.

Verification performed locally (all pass):

  • tests/pages-page-data.test.ts — 26 passed
  • tests/pages-router.test.ts — 3 new notFound + gssp-throw integration tests passed
  • tests/entry-templates.test.ts — 24 passed
  • vp check on the 3 changed server files — clean

What I confirmed:

  • Core design mirrors Next.js render404() (typed notFound signal for HTML, JSON 404 envelope for /_next/data, generated entry owns /404/_error fallback).
  • __findPagesNotFoundRoute() is safer than the old matchRoute("/404"); recursion guard prevents infinite loops.
  • err forwarded only on the SSR-throw path, not the notFound recursion — correct.
  • req.url/asPath flow into _error.getInitialProps correctly.
  • The hasPagesGetInitialProps gate keeps the static-page hot path allocation-free.
  • prod-server.ts inherits the logic via the built entry — no separate parity gap.

New observation raised (non-blocking):

  1. This PR newly invokes page-component getInitialProps in the prod resolver for the first time — previously prod never ran page-level gIP. This is the Next.js-correct behavior and is well-tested, but it's a broader behavioral change than the PR title/summary suggests. Recommended it be called out explicitly in the changelog so apps relying on client-only gIP fallback aren't surprised.
  2. (Inline) Minor dev/prod symmetry note — the dev gIP block isn't gated on hasPagesGetInitialProps like the prod path now is; functionally fine, just a readability suggestion.

github run

@james-elicx
james-elicx merged commit 494e8d2 into cloudflare:main Jun 5, 2026
31 checks passed
@github-actions github-actions Bot mentioned this pull request Jun 5, 2026
@NathanDrake2406
NathanDrake2406 deleted the nathan/fix-not-found-req-url branch June 13, 2026 13:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants