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
- Pass an explicit boolean: `hasRootLayout={true}` when a root layout route exists, `false` otherwise.
- Derive it from your route config instead of hardcoding: check whether a root `layout.tsx`/root route is defined.
- If spreading props, default the key: `{ ...props, hasRootLayout: props.hasRootLayout ?? false }`.
- 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
- Always pass hasRootLayout explicitly when using UNSAFE_RSCDefaultRootErrorBoundary.
- Derive the value from route config (does a root layout exist) rather than trusting optional context.
- Re-check custom error boundary code after upgrading the RSC APIs.
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
- Module cannot have both an ErrorBoundary export and a Server
- The "@vitejs/plugin-rsc" plugin should be placed after the R
- When using the React Router `basename` and the Vite `base` c
- Prerender (data): Received a ${response.status} status code
- Module cannot have both a default export and a ServerCompone
AI-assisted analysis of remix-run/react-router@6beaca3952 (2026-08-18).
Data as JSON: /api/errors/4437b286c61999c3.
Report an issue: GitHub.