Skip to content

Next.js error

notFound() Is Not Allowed to Use in Root Layout

The error

notFound() is not allowed to use in root layout

The root layout renders the not-found page, so it cannot be the thing that triggers it. Whatever check lives there has to move down a level or become a redirect.

notFound() is not allowed to use in root layout

The root layout is the one that holds <html> and <body>. Every page in the application renders inside it, and that includes not-found.tsx.

So a root layout calling notFound() is asking to render the not-found page inside the component that is currently failing. There is no layout above it to wrap the result, and Next refuses rather than recursing.

The usual cause is validation that drifted upward

// app/layout.tsx - the root
export default async function RootLayout({ params, children }) {
  const { locale } = await params
  if (!routing.locales.includes(locale)) notFound()   // throws the error above
  return <html lang={locale}><body>{children}</body></html>
}

The check is correct. The place is not.

Move it down one level

Separate the document shell from the thing that validates:

// app/layout.tsx - holds the document, decides nothing
export default function RootLayout({ children }) {
  return children
}
 
// app/[locale]/layout.tsx - validates, and may call notFound()
export default async function LocaleLayout({ params, children }) {
  const { locale } = await params
  if (!hasLocale(routing.locales, locale)) notFound()
  return <html lang={locale} dir={dirFor(locale)}><body>{children}</body></html>
}

The locale layout is not the root, so notFound() is allowed there, and the root above it can still render the result. This is the shape an internationalised App Router application wants anyway, and the error is a reasonable prompt to adopt it.

Or decide before rendering starts

If the answer is knowable from the URL, the proxy is a better place than any layout - the request never reaches rendering, so there is no layout question at all.

That is also where a redirect usually beats a 404. An unknown locale prefix in front of a real path is a visitor who wants a page you have; sending them to it with a 308 is more useful than a not-found page, and it keeps whatever link pointed there from being wasted.

What the restriction is actually protecting

Not an arbitrary rule. not-found.tsx renders inside the root layout, so if the root layout can trigger it, rendering the result re-runs the thing that triggered it. The error is Next declining to find that out at runtime.

redirect() has no such problem and works fine from a root layout, because a redirect response has nothing to wrap.

Layout boundaries that drifted - validation in the root, data fetching in a layout that every route pays for - are a common finding when we take on an existing App Router codebase, and they are usually cheap to move once somebody notices.

Related questions

Where should the check go instead?
Into a layout or a page below the root, or into the proxy if the decision can be made from the URL alone. A nested layout can call notFound() because the root layout is still above it to render the result.
We validate the locale in the root layout. What is the alternative?
Decide it before rendering. next-intl's `hasLocale` check with `notFound()` belongs in `app/[locale]/layout.tsx`, which is not the root layout in that structure - the root is the one holding `<html>`. If your `<html>` tag is in the locale layout, that is the thing to separate first.
Can we redirect instead?
Often yes, and it is frequently the better answer for a user. A wrong locale prefix or a legacy path is better sent somewhere real with a 308 than shown a 404, and a redirect from the proxy never reaches rendering at all.
Does the same restriction apply to `redirect()`?
No. `redirect()` from a root layout works, because the response is a redirect rather than a rendered page - there is nothing to wrap. It is `notFound()` specifically that needs a layout above it.
Call us+1 848 272 7583WhatsApp+90 850 308 5436Emailinfo@codefacture.comContact page