{"record":{"id":"639d4dbeef1b95ad","repo":"remix-run/react-router","slug":"reactrouterconfigfile-must-export-a-config","errorCode":null,"errorMessage":"${reactRouterConfigFile} must export a config","messagePattern":"(.+?) must export a config","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/react-router-dev/config/config.ts","lineNumber":471,"sourceCode":"}): Promise<ConfigResult> {\n  let reactRouterUserConfig: ReactRouterConfig = {};\n\n  if (reactRouterConfigFile) {\n    try {\n      if (!fs.existsSync(reactRouterConfigFile)) {\n        return err(`${reactRouterConfigFile} no longer exists`);\n      }\n\n      let configModule = await viteRunnerContext.runner.import(\n        reactRouterConfigFile,\n      );\n\n      if (configModule.default === undefined) {\n        return err(`${reactRouterConfigFile} must provide a default export`);\n      }\n\n      if (typeof configModule.default !== \"object\") {\n        return err(`${reactRouterConfigFile} must export a config`);\n      }\n\n      reactRouterUserConfig = configModule.default;\n\n      if (validateConfig) {\n        const error = validateConfig(reactRouterUserConfig);\n        if (error) {\n          return err(error);\n        }\n      }\n    } catch (error) {\n      return err(`Error loading ${reactRouterConfigFile}: ${error}`);\n    }\n  }\n\n  // Prevent mutations to the user config\n  reactRouterUserConfig = deepFreeze(cloneDeep(reactRouterUserConfig));\n","sourceCodeStart":453,"sourceCodeEnd":489,"githubUrl":"https://github.com/remix-run/react-router/blob/6beaca39526d5716c3c112ebb0782765baa5a9ce/packages/react-router-dev/config/config.ts#L453-L489","documentation":"The config file has a default export, but `typeof configModule.default !== \"object\"` — it is a string, number, boolean, function, or similar non-object value. React Router expects the default export to be a plain config object whose keys are option names (`ssr`, `prerender`, `buildDirectory`, ...), so any primitive (or function) default export is rejected before further processing.","triggerScenarios":"Default-exporting a primitive or function from `react-router.config.ts`, e.g. `export default \"ssr\"`, `export default 42`, or `export default () => ({ ssr: true })` (a function is `typeof \"function\"`, not `\"object\"`).","commonSituations":"Attempting a 'lazy config' pattern (`export default () => config`) which React Router does not support; typos like `export default ssr;` where `ssr` is a boolean variable; converting a JSON config import into a JS value of the wrong shape.","solutions":["Change the default export to a plain object literal containing the config options.","If you wanted a function-style config, compute the object first and export the result.","Check for accidental re-export of an option value instead of the config object.","Re-run the build/dev command to confirm the error clears."],"exampleFix":"// before: react-router.config.ts\nexport default () => ({ ssr: true }); // function, not object\n\n// after\nexport default {\n  ssr: true,\n};","handlingStrategy":"type-guard","validationCode":"import cfg from \"./react-router.config\";\nif (typeof cfg !== \"object\" || cfg === null || Array.isArray(cfg) === undefined) {\n  // mirror of the library check\n}\nif (typeof cfg !== \"object\" || cfg === null) {\n  throw new Error(\"react-router config default export must be a plain object\");\n}","typeGuard":"function isPlainObjectConfig(v: unknown): v is Record<string, unknown> {\n  return typeof v === \"object\" && v !== null && !Array.isArray(v);\n}","tryCatchPattern":null,"preventionTips":["Export an object literal, never a function or primitive.","If you compute config conditionally, compute first then `export default result`.","Add `satisfies ReactRouterConfig` (type-only) to catch shape mistakes in your editor."],"tags":["config","es-modules","type-mismatch","build"],"backgroundTag":"config-type-mismatch","analyzedSha":"6beaca39526d5716c3c112ebb0782765baa5a9ce","analyzedAt":"2026-08-18T18:04:14.938Z","contentChangedAt":"2026-08-18T18:04:14.938Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}