{"record":{"id":"4437b286c61999c3","repo":"remix-run/react-router","slug":"missing-hasrootlayout-prop","errorCode":null,"errorMessage":"Missing 'hasRootLayout' prop","messagePattern":"Missing 'hasRootLayout' prop","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/react-router/lib/rsc/errorBoundaries.tsx","lineNumber":172,"sourceCode":"          overflow: \"auto\",\n        }}\n      >\n        {errorInstance.stack}\n      </pre>\n      {heyDeveloper}\n    </ErrorWrapper>\n  );\n}\n\nexport function RSCDefaultRootErrorBoundary({\n  hasRootLayout,\n}: {\n  hasRootLayout: boolean;\n}) {\n  let error = useRouteError();\n\n  if (hasRootLayout === undefined) {\n    throw new Error(\"Missing 'hasRootLayout' prop\");\n  }\n  return (\n    <RSCDefaultRootErrorBoundaryImpl\n      renderAppShell={!hasRootLayout}\n      error={error}\n    />\n  );\n}\n","sourceCodeStart":154,"sourceCodeEnd":181,"githubUrl":"https://github.com/remix-run/react-router/blob/6beaca39526d5716c3c112ebb0782765baa5a9ce/packages/react-router/lib/rsc/errorBoundaries.tsx#L154-L181","documentation":"`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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nexport const ErrorBoundary = UNSAFE_RSCDefaultRootErrorBoundary;\n// or\n<UNSAFE_RSCDefaultRootErrorBoundary hasRootLayout={cfg?.hasRootLayout} />\n\n// after\nexport function ErrorBoundary() {\n  return <UNSAFE_RSCDefaultRootErrorBoundary hasRootLayout={true} />;\n}","handlingStrategy":"validation","validationCode":"if (typeof hasRootLayout !== \"boolean\") {\n  throw new TypeError(\"RSCDefaultRootErrorBoundary requires a boolean hasRootLayout prop\");\n}","typeGuard":"const hasRootLayoutProp = (\n  props: { hasRootLayout?: unknown },\n): props is { hasRootLayout: boolean } =>\n  typeof props.hasRootLayout === \"boolean\";","tryCatchPattern":null,"preventionTips":["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."],"tags":["rsc","error-boundary","missing-prop","root-route"],"backgroundTag":"missing-required-argument","analyzedSha":"6beaca39526d5716c3c112ebb0782765baa5a9ce","analyzedAt":"2026-08-18T18:04:14.938Z","contentChangedAt":"2026-08-18T18:04:14.938Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}