#5036·nextra

Bug: `<Layout>` always throws "Invalid input: expected nonoptional, received undefined → at children"

Author: GitHubGWCreated Jul 28, 2026Updated Sep 17, 2026
Labelsbug

Describe the bug

<Layout> from nextra-theme-docs throws a Zod validation error on every single render, regardless of how it's used:

Error: ✖ Invalid input: expected nonoptional, received undefined
  → at children

This happens because the compiled Layout component destructures children out of its props via object rest spread before validating the remaining props against LayoutPropsSchema — but LayoutPropsSchema.children is a required (non-optional) field. JS rest destructuring always removes the destructured key from the rest object entirely (not just sets it to undefined), and Zod treats "key missing" differently from "key present but undefined" for required fields — so validation always fails.

To Reproduce

Steps to reproduce the behavior:

  1. Set up a minimal Next.js App Router + Nextra project following the "Get Started" guide.
  2. Use <Layout> normally in app/layout.tsx:
    typescript
    <Layout
      banner={banner}
      navbar={navbar}
      pageMap={pageMap}
      footer={footer}
    >
      {children}
    </Layout>
  3. Run next dev.
  4. Visit any page (e.g. /).
  5. See error in terminal/browser overlay.

This reproduces 100% of the time, independent of page content, bundler (webpack/Turbopack), or Next.js version (confirmed on Next.js 15.5.22 and 16.2.12).

Root cause

In nextra-theme-docs/dist/layout.js:

javascript
const Layout = (t0) => {
  ...
  ({ children, ...themeConfig } = t0);
  ...
  const { data, error } = LayoutPropsSchema.safeParse(themeConfig);
  if (error) {
    throw z.prettifyError(error);
  }
  ...

{ children, ...themeConfig } removes the children key from themeConfig entirely. In nextra-theme-docs/dist/schemas.js:

javascript
const LayoutPropsSchema = z.strictObject({
  banner: reactNode.optional().meta({...}),
  children: reactNode,   // <-- required, no `.optional()`
  ...

children has no .optional(). Minimal Zod v4 repro confirming the "missing key" vs "key present but undefined" distinction:

javascript
import { z } from 'zod'

const reactNode = z.custom(data => data == null || typeof data === 'string')
const schema = z.strictObject({ children: reactNode })

schema.safeParse({}).error?.issues
// → [{ code: 'invalid_type', expected: 'nonoptional', path: ['children'], message: 'Invalid input: expected nonoptional, received undefined' }]

schema.safeParse({ children: undefined }).error
// → undefined (passes!)

Even though reactNode's own custom check explicitly allows null/undefined, that check never runs, because Zod rejects the missing key before reaching the custom validator.

Confirmed this affects both [email protected] and 4.6.1 (identical destructuring pattern in the compiled output of both).

Suggested fix

Either of these fixes the issue:

  1. Add .optional() to the children field in LayoutPropsSchema:
    diff
    const LayoutPropsSchema = z.strictObject({
      banner: reactNode.optional().meta({...}),
    - children: reactNode,
    + children: reactNode.optional(),
  2. Or don't strip children from the object passed to .safeParse() — validate the full props object (including children) instead of the rest-destructured themeConfig.

I verified locally that fix #1 resolves the issue and <Layout> renders correctly afterward.

Expected behavior

<Layout> should render normally without throwing a validation error when used with standard props as shown in the official docs.

Screenshots

Image

Desktop (please complete the following information):

  • OS: macOS
  • Package versions:
    • next: 16.2.12
    • nextra: 4.6.1
    • nextra-theme-docs: 4.6.1 (also reproduced on 4.5.1)
    • zod: 4.4.3
    • react / react-dom: 19.2.8
    • Node.js: 24.18.0

Smartphone:

N/A (server-side build/runtime error, not device-specific)

Additional context

Workaround: patching node_modules/nextra-theme-docs/dist/schemas.js locally to change children: reactNodechildren: reactNode.optional() (e.g. via patch-package) unblocks local development.