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

Server HTML For NotFound() Is An Empty Shell Without Root Layout And Lang Attribute

When a page calls notFound(), Next.js serves a minimal error shell (`__next_error__`) in the server HTML, omitting the root layout, `<html lang>` attribute, and the nearest not-found UI. This breaks accessibility, no-JS clients, and dynamic root layouts, and is inconsistent with the hydrated result. Affects App Router across multiple Next.js versions.

highConfidence 85%Next.jsAffected V14.2.33Affected V15.5.4Affected V16.2.11Affected V16.3.7Affected V16.5.0-Canary.2

Origin Analysis

Next.js treats notFound() thrown during server rendering as a top-level error and renders a dedicated error shell without including the root layout or nearest not-found boundary. The global-not-found feature only covers unmatched URLs, so programmatic notFound bypasses the layout tree.
1. Create an App Router project with root layout (including `lang`), root not-found.tsx, and a dynamic page that calls notFound() for certain params. 2. Build and start the server. 3. `curl` a missing route: the HTML is `<html id="__next_error__">` with empty body, no lang, no layout, no not-found output. 4. Open the same route in a browser: after hydration the correct layout and not-found UI appear.

Fixing Code Block

Edge Case Audit

This change may affect streaming, caching, and error boundary behavior. Thorough testing is required for dynamic routes, ISR, and concurrent rendering. Potential issues: double rendering of layout if not-found component itself throws, or infinite loop if notFound is called again in not-found. Defensive measure: ensure a flag to prevent re-entry and fallback to original shell if an error occurs during not-found rendering. Rollback: revert to the previous commit or disable the new behavior behind a flag if regressions appear.

Ecosystem Topology