remix-run/react-router · error · Error

Missing 'hasRootLayout' prop

Error message

Missing 'hasRootLayout' prop

What it means

`RSCDefaultRootErrorBoundary` (exported as `UNSAFE_RSCDefaultRootErrorBoundary` for use in custom RSC setups) decides whether to render the full app shell around the error based on the required boolean prop `hasRootLayout`. Because the prop is typed `boolean` but checked at runtime against `undefined`, omitting it or passing `undefined` throws immediately — a props contract violation, not a rendering failure.

Source

Thrown at packages/react-router/lib/rsc/errorBoundaries.tsx:172

          overflow: "auto",
        }}
      >
        {errorInstance.stack}
      </pre>
      {heyDeveloper}
    </ErrorWrapper>
  );
}

export function RSCDefaultRootErrorBoundary({
  hasRootLayout,
}: {
  hasRootLayout: boolean;
}) {
  let error = useRouteError();

  if (hasRootLayout === undefined) {
    throw new Error("Missing 'hasRootLayout' prop");
  }
  return (
    <RSCDefaultRootErrorBoundaryImpl
      renderAppShell={!hasRootLayout}
      error={error}
    />
  );
}

View on GitHub (pinned to 6beaca3952)

Solutions

  1. Pass an explicit boolean: `hasRootLayout={true}` when a root layout route exists, `false` otherwise.
  2. Derive it from your route config instead of hardcoding: check whether a root `layout.tsx`/root route is defined.
  3. If spreading props, default the key: `{ ...props, hasRootLayout: props.hasRootLayout ?? false }`.
  4. Check the version's docs/examples for the expected root error boundary setup after upgrading.

Example fix

// before
export const ErrorBoundary = UNSAFE_RSCDefaultRootErrorBoundary;
// or
<UNSAFE_RSCDefaultRootErrorBoundary hasRootLayout={cfg?.hasRootLayout} />

// after
export function ErrorBoundary() {
  return <UNSAFE_RSCDefaultRootErrorBoundary hasRootLayout={true} />;
}
Defensive patterns

Strategy: validation

Validate before calling

if (typeof hasRootLayout !== "boolean") {
  throw new TypeError("RSCDefaultRootErrorBoundary requires a boolean hasRootLayout prop");
}

Type guard

const hasRootLayoutProp = (
  props: { hasRootLayout?: unknown },
): props is { hasRootLayout: boolean } =>
  typeof props.hasRootLayout === "boolean";

Prevention

When it happens

Trigger: Using `UNSAFE_RSCDefaultRootErrorBoundary` in a custom root error boundary without passing `hasRootLayout`; computing the prop conditionally so it evaluates to `undefined` (e.g., `hasRootLayout={cfg?.hasRootLayout}` with cfg missing); copying example code from a different version whose entry passed the prop automatically.

Common situations: Building custom `ErrorBoundary` exports for the root route in RSC framework mode; upgrading between versions where the required prop was introduced; passing spread props (`{...props}`) that no longer include the key.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


AI-assisted analysis of remix-run/react-router@6beaca3952 (2026-08-18). Data as JSON: /api/errors/4437b286c61999c3. Report an issue: GitHub.