{"record":{"id":"c2a20f09088d8a26","repo":"remix-run/react-router","slug":"the-routediscovery-mode-config-cannot-be-set-to","errorCode":null,"errorMessage":"The `routeDiscovery.mode` config cannot be set to \"lazy\" when setting `ssr:false`","messagePattern":"The `routeDiscovery\\.mode` config cannot be set to \"lazy\" when setting `ssr:false`","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/react-router-dev/config/config.ts","lineNumber":599,"sourceCode":"      );\n    }\n  }\n\n  let routeDiscovery: ResolvedReactRouterConfig[\"routeDiscovery\"];\n  if (userRouteDiscovery == null) {\n    if (ssr) {\n      routeDiscovery = {\n        mode: \"lazy\",\n        manifestPath: \"/__manifest\",\n      };\n    } else {\n      routeDiscovery = { mode: \"initial\" };\n    }\n  } else if (userRouteDiscovery.mode === \"initial\") {\n    routeDiscovery = userRouteDiscovery;\n  } else if (userRouteDiscovery.mode === \"lazy\") {\n    if (!ssr) {\n      return err(\n        'The `routeDiscovery.mode` config cannot be set to \"lazy\" when setting `ssr:false`',\n      );\n    }\n\n    let { manifestPath } = userRouteDiscovery;\n    if (manifestPath != null && !manifestPath.startsWith(\"/\")) {\n      return err(\n        \"The `routeDiscovery.manifestPath` config must be a root-relative \" +\n          'pathname beginning with a slash (i.e., \"/__manifest\")',\n      );\n    }\n\n    routeDiscovery = userRouteDiscovery;\n  }\n\n  let appDirectory = Path.resolve(root, userAppDirectory || \"app\");\n  let buildDirectory = Path.resolve(root, userBuildDirectory);\n","sourceCodeStart":581,"sourceCodeEnd":617,"githubUrl":"https://github.com/remix-run/react-router/blob/6beaca39526d5716c3c112ebb0782765baa5a9ce/packages/react-router-dev/config/config.ts#L581-L617","documentation":"`routeDiscovery.mode: \"lazy\"` relies on a server-side manifest endpoint (`/__manifest`) that only exists when SSR is enabled. With `ssr: false` (SPA mode) there is no server to serve the manifest, so this combination is rejected; SPA mode must use `routeDiscovery.mode: \"initial\"` (which is the default when `ssr: false`).","triggerScenarios":"A config containing both `ssr: false` and `routeDiscovery: { mode: \"lazy\" }` — typically left over from an SSR setup being converted to SPA mode, where only the `ssr` flag was flipped.","commonSituations":"Converting an SSR app to an SPA by setting `ssr: false` without adjusting route discovery; copying a config between projects with different SSR settings; explicit opt-in to lazy discovery during a migration to `ssr: false` for static hosting.","solutions":["Remove the `routeDiscovery` block entirely — with `ssr: false` it defaults to `initial`, which is what SPAs need.","Or set it explicitly: `routeDiscovery: { mode: \"initial\" }`.","If you intended SSR, restore `ssr: true` and keep `mode: \"lazy\"`.","Re-run the build to confirm config validation passes."],"exampleFix":"// before\nexport default {\n  ssr: false,\n  routeDiscovery: { mode: \"lazy\", manifestPath: \"/__manifest\" },\n};\n\n// after\nexport default {\n  ssr: false,\n  routeDiscovery: { mode: \"initial\" },\n};","handlingStrategy":"validation","validationCode":"const cfg = { ssr: false } as ReactRouterConfig;\nif (cfg.ssr === false && cfg.routeDiscovery?.mode === \"lazy\") {\n  throw new Error(\"SPA mode requires routeDiscovery.mode 'initial'\");\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["When flipping ssr to false, delete the whole routeDiscovery block (the default is correct for SPA).","Keep a single source of truth for 'is this app SSR or SPA' and derive both flags from it.","Remember lazy discovery needs the SSR runtime's /__manifest endpoint — no server, no lazy."],"tags":["config","spa","ssr","route-discovery","validation"],"backgroundTag":"incompatible-config-combination","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"}