{"record":{"id":"d7ef9e408d17cae8","repo":"remix-run/remix","slug":"route-module-routesfile-must-export-a-named-ro","errorCode":null,"errorMessage":"Route module ${routesFile} must export a named \"routes\" value.","messagePattern":"Route module (.+?) must export a named \"routes\" value\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/cli/src/lib/load-route-map-worker.ts","lineNumber":30,"sourceCode":"\n  setExitCode(1)\n})\n\nasync function run(): Promise<void> {\n  let routesFile = process.argv[2]\n  if (typeof routesFile !== 'string' || routesFile.length === 0) {\n    throw new Error('Missing app/routes.ts path.')\n  }\n\n  let tree = await loadRawRouteTree(routesFile)\n  process.stdout.write(JSON.stringify(tree))\n}\n\nasync function loadRawRouteTree(routesFile: string): Promise<RawRouteTreeNode[]> {\n  let routeModule: object = await import(pathToFileURL(routesFile).href)\n\n  if (!('routes' in routeModule)) {\n    throw new Error(`Route module ${routesFile} must export a named \"routes\" value.`)\n  }\n\n  return normalizeRouteGroup(routeModule.routes, [], new Map())\n}\n\nfunction normalizeRouteGroup(\n  value: unknown,\n  parentSegments: string[],\n  seen: Map<object, string>,\n): RawRouteTreeNode[] {\n  if (!isPlainObject(value)) {\n    let location = parentSegments.length === 0 ? 'routes' : parentSegments.join('.')\n    throw new Error(`Invalid route map value at \"${location}\". Expected a nested route object.`)\n  }\n\n  let existingPath = seen.get(value)\n  let currentPath = parentSegments.length === 0 ? 'routes' : parentSegments.join('.')\n  if (existingPath != null) {","sourceCodeStart":12,"sourceCodeEnd":48,"githubUrl":"https://github.com/remix-run/remix/blob/9696913134be3a4423513d2775f7b31d6917c049/packages/cli/src/lib/load-route-map-worker.ts#L12-L48","documentation":"The route-map worker imports your app/routes.ts module and requires it to export a named `routes` value (the framework 3 config-based routing entry point). If the module has no `routes` export, the worker throws before parsing anything.","triggerScenarios":"app/routes.ts (or the configured route-map file) exports only `default`, only types, or nothing at all — e.g. `export default [{ path: '/' }]` instead of `export let routes = {...}`.","commonSituations":"Migrating from file-based routing or React Router style config and keeping a default export; leftover placeholder routes.ts created empty; typos like `export const route =` (singular).","solutions":["Add a named `routes` export: `export let routes = {...}` in app/routes.ts","If using an empty route set temporarily, export an empty object `export let routes = {}`","Check for accidental `default` export and move it to a named `routes` export"],"exampleFix":"// before (app/routes.ts)\nexport default { root: '/' }\n// after\nexport let routes = { root: '/' }","handlingStrategy":"type-guard","validationCode":"let mod = await import(pathToFileURL(routesPath).href)\nif (!('routes' in mod)) throw new Error('app/routes.ts must export `routes`')","typeGuard":"function hasRoutesExport(mod: object): mod is { routes: unknown } {\n  return 'routes' in mod\n}","tryCatchPattern":null,"preventionTips":["Use `export let routes = {...}` in app/routes.ts","Run `remix routes` after creating the file to catch mistakes early","Avoid default exports in the route map module"],"tags":["routes","config","cli","migration"],"backgroundTag":"missing-exported-config","analyzedSha":"9696913134be3a4423513d2775f7b31d6917c049","analyzedAt":"2026-08-27T19:55:01.024Z","schemaVersion":2},"datasetVersion":"2026-08-28T00:17:15.603Z"}