{"record":{"id":"2066a2f391b12e3c","repo":"remix-run/react-router","slug":"module-cannot-have-both-a-layout-export-and-a-serv","errorCode":null,"errorMessage":"Module cannot have both a Layout export and a ServerLayout export","messagePattern":"Module cannot have both a Layout export and a ServerLayout export","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/react-router-dev/vite/rsc/virtual-route-config.ts","lineNumber":32,"sourceCode":"  let code = js`import * as React from \"react\";\nfunction frameworkRoute(lazy) {\n  return async () => {\n    const mod = await lazy();\n    let Component;\n    let Layout;\n    let ErrorBoundary;\n    let HydrateFallback;\n    if (\"default\" in mod && mod.default) {\n      if (\"ServerComponent\" in mod && mod.ServerComponent) {\n        throw new Error(\"Module cannot have both a default export and a ServerComponent export\");\n      }\n      Component = mod.default;\n    } else if (\"ServerComponent\" in mod && mod.ServerComponent) {\n      Component = mod.ServerComponent;\n    }\n    if (\"Layout\" in mod && mod.Layout) {\n      if (\"ServerLayout\" in mod && mod.ServerLayout) {\n        throw new Error(\"Module cannot have both a Layout export and a ServerLayout export\");\n      }\n      Layout = mod.Layout;\n    } else if (\"ServerLayout\" in mod && mod.ServerLayout) {\n      Layout = mod.ServerLayout;\n    }\n    if (\"ErrorBoundary\" in mod && mod.ErrorBoundary) {\n      if (\"ServerErrorBoundary\" in mod && mod.ServerErrorBoundary) {\n        throw new Error(\n          \"Module cannot have both an ErrorBoundary export and a ServerErrorBoundary export\",\n        );\n      }\n      ErrorBoundary = mod.ErrorBoundary;\n    } else if (\"ServerErrorBoundary\" in mod && mod.ServerErrorBoundary) {\n      ErrorBoundary = mod.ServerErrorBoundary;\n    }\n    if (\"HydrateFallback\" in mod && mod.HydrateFallback) {\n      if (\"ServerHydrateFallback\" in mod && mod.ServerHydrateFallback) {\n        throw new Error(","sourceCodeStart":14,"sourceCodeEnd":50,"githubUrl":"https://github.com/remix-run/react-router/blob/6beaca39526d5716c3c112ebb0782765baa5a9ce/packages/react-router-dev/vite/rsc/virtual-route-config.ts#L14-L50","documentation":"In RSC mode a route's layout can be supplied either by the client 'Layout' export or by the server 'ServerLayout' export. The framework-route wrapper resolves them in order — client 'Layout' first — and throws when both are truthy, since rendering would be ambiguous between a client layout and a server layout for the same route.","triggerScenarios":"A route module exporting both 'export function Layout({ children })' and 'export function ServerLayout({ children })' with both truthy.","commonSituations":"Migrating a layout route to server-side rendering by adding ServerLayout on top of an existing Layout export; merging two example route files during RSC adoption.","solutions":["Keep only 'ServerLayout' when the layout must run on the server","Keep only 'Layout' when the layout needs state/effects on the client","Extract shared markup into a component module imported by whichever layout remains"],"exampleFix":"// before\nexport function Layout({ children }) { return <div>{children}</div>; }\nexport function ServerLayout({ children }) { return <Shell>{children}</Shell>; }\n\n// after\nexport function ServerLayout({ children }) { return <Shell>{children}</Shell>; }","handlingStrategy":"validation","validationCode":"const PAIRS = [[\"Layout\", \"ServerLayout\"]] as const;\nfor (const file of routeFiles) {\n  const mod: Record<string, unknown> = await import(pathToFileURL(file).href);\n  for (const [client, server] of PAIRS) {\n    if (mod[client] && mod[server]) {\n      throw new Error(`${file}: export either ${client} or ${server}, not both`);\n    }\n  }\n}","typeGuard":"function hasLayoutConflict(mod: Record<string, unknown>): boolean {\n  return Boolean(mod.Layout) && Boolean(mod.ServerLayout);\n}","tryCatchPattern":null,"preventionTips":["Pick one layout variant per route and delete the other during migration","Keep shared layout markup in a separate imported component","Let the build-time pair validator (error 47) run in CI"],"tags":["rsc","route-module","exports","layout","naming"],"backgroundTag":"mutually-exclusive-exports","analyzedSha":"6beaca39526d5716c3c112ebb0782765baa5a9ce","analyzedAt":"2026-08-18T18:04:14.938Z","contentChangedAt":"2026-08-18T18:04:14.938Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}