notFound() serves an empty `__next_error__` document instead of not-found.tsx
Link to the code that reproduces this issue
https://github.com/franknoel/next-notfound-ssr
To Reproduce
- Clone the reproduction and run
npm install. - Run
npm run build && npm run start(npm run devshows the same thing). - Run
./check.sh, or fetch the pages by hand:
curl -s http://localhost:3000/missing # page that calls notFound()
curl -s http://localhost:3000/no/such/route # URL that matches no routeThe app has three files: a root layout with <html lang="en">, an app/not-found.tsx that renders NOT FOUND BOUNDARY, and app/[slug]/page.tsx, which calls notFound() unless the slug is known.
Current vs. Expected behavior
Current: /missing answers 404, but its HTML is <html id="__next_error__"><head></head><body> plus scripts. The root layout does not render, so there is no lang and none of the not-found.tsx markup. That markup exists only in the RSC payload, so the page is blank until it hydrates, and stays blank without JavaScript.
An unmatched URL (/no/such/route) is fine: it renders not-found.tsx inside the root layout.
check.sh output, the same on 16.3.6 and 16.4.0-canary.48, in next dev and in next build && next start:
/known 200 <html lang="en"> boundary/page text in HTML: yes
/missing 404 <html id="__next_error__"> boundary/page text in HTML: no
/no/such/route 404 <html lang="en"> boundary/page text in HTML: yesExpected: /missing renders like /no/such/route: the root layout with NOT FOUND BOUNDARY in the server HTML, and the same 404 status.
Provide environment information
Operating System:
Platform: darwin
Arch: arm64
Version: Darwin Kernel Version 25.6.0: Tue Aug 18 17:49:13 PDT 2026; root:xnu-12377.161.15.700.19~2/RELEASE_ARM64_T6000
Available memory (MB): 32768
Available CPU cores: 10
Binaries:
Node: 24.21.0
npm: 11.19.0
Yarn: 1.22.22
pnpm: 9.15.9
Relevant Packages:
next: 16.3.6 // Latest available version is detected (16.3.6).
eslint-config-next: N/A
react: 19.2.8
react-dom: 19.2.8
typescript: 5.9.3
Next.js Config:
output: N/AWhich area(s) are affected? (Select all that apply)
Not Found, Error Handling
Which stage(s) are affected? (Select all that apply)
next dev (local), next build (local), next start (local), Vercel (Deployed)
Additional context
Also reproduces on [email protected], dev and prod.
Same bug as #98295 and #98954, which were closed automatically for lacking a reproduction link.
Where it seems to happen: HTTPAccessFallbackBoundary is a client error boundary, and React does not run error boundaries during server rendering, so the notFound() throw escapes the Fizz shell. The catch in app-render (renderToStream, and prerenderToStream for ISR) sets the 404 status and renders getErrorRSCPayload, whose seed is the hardcoded __next_error__ document. Because the status and the empty document come from the same catch, an app cannot get a 404 with real HTML from notFound().
We hit it on a site with locale-prefixed routes: every unknown page and event URL is served without lang or any text.
Source: vercel/next.js