{"record":{"id":"647a5880611d683f","repo":"remix-run/react-router","slug":"expected-a-route-id-in-react-router-processroutes","errorCode":null,"errorMessage":"Expected a route.id in react-router processRoutes() function","messagePattern":"Expected a route\\.id in react-router processRoutes\\(\\) function","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/react-router/lib/dom/ssr/routes-test-stub.tsx","lineNumber":189,"sourceCode":"\n    return (\n      <FrameworkContext.Provider value={frameworkContextRef.current}>\n        <RouterProvider router={routerRef.current} />\n      </FrameworkContext.Provider>\n    );\n  };\n}\n\nfunction processRoutes(\n  routes: StubRouteObject[],\n  context: RouterContextProvider,\n  manifest: AssetsManifest,\n  routeModules: RouteModules,\n  parentId?: string,\n): DataRouteObject[] {\n  return routes.map((route) => {\n    if (!route.id) {\n      throw new Error(\n        \"Expected a route.id in react-router processRoutes() function\",\n      );\n    }\n\n    let newRoute: DataRouteObject = {\n      id: route.id,\n      path: route.path,\n      index: route.index,\n      Component: route.Component\n        ? withComponentProps(route.Component)\n        : undefined,\n      HydrateFallback: route.HydrateFallback\n        ? withHydrateFallbackProps(route.HydrateFallback)\n        : undefined,\n      ErrorBoundary: route.ErrorBoundary\n        ? withErrorBoundaryProps(route.ErrorBoundary)\n        : undefined,\n      action: route.action","sourceCodeStart":171,"sourceCodeEnd":207,"githubUrl":"https://github.com/remix-run/react-router/blob/6beaca39526d5716c3c112ebb0782765baa5a9ce/packages/react-router/lib/dom/ssr/routes-test-stub.tsx#L171-L207","documentation":"`createRoutesStub()` converts your stub route objects into data routes and then walks them with `processRoutes()`, which requires every route to have a truthy `id`. The converter auto-generates tree-path ids, but an explicit `id: \"\"` (empty string) survives conversion and is falsy, so the stub throws this invariant. It is a test-utility error: it only fires inside `createRoutesStub`/`createRoutesStub`-powered unit tests.","triggerScenarios":"Passing a route object with `id: \"\"` to `createRoutesStub(routes)`; spreading a route config where an optional `id` field is present but an empty string; reusing real-app route objects whose ids were conditionally assigned and ended up as empty strings.","commonSituations":"Unit-testing components with `createRoutesStub` while mapping real route configs into stubs; generating ids programmatically (`id: route.id ?? \"\"`) instead of omitting the key; copy-pasting a route object and clearing the id during test setup.","solutions":["Remove the empty `id` field so the stub auto-assigns one, or set a unique non-empty id like `id: \"0-1-2\"` or `id: \"layout\"`.","Audit test fixtures for `id: \"\"` produced by spreads or defaults.","If building stub routes from app routes, filter/normalize ids before calling `createRoutesStub`."],"exampleFix":"// before\ncreateRoutesStub([\n  { id: \"\", path: \"/\", Component: Home, loader },\n]);\n\n// after\ncreateRoutesStub([\n  { path: \"/\", Component: Home, loader },\n]);","handlingStrategy":"validation","validationCode":"const hasValidIds = (routes: StubRouteObject[]): boolean =>\n  routes.every(\n    (r) =>\n      r.id !== \"\" &&\n      (!r.children || hasValidIds(r.children)),\n  );\nif (!hasValidIds(stubRoutes)) throw new Error(\"stub routes have empty ids\");\nconst Stub = createRoutesStub(stubRoutes);","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Omit the id field in stub routes unless you need a stable id; the stub auto-generates tree-path ids.","Never default ids to empty strings when mapping app routes to stub routes.","Keep test fixtures type-checked against StubRouteObject."],"tags":["testing","create-routes-stub","route-id","validation"],"backgroundTag":"missing-required-config-field","analyzedSha":"6beaca39526d5716c3c112ebb0782765baa5a9ce","analyzedAt":"2026-08-18T18:04:14.938Z","schemaVersion":2},"datasetVersion":"2026-09-01T03:17:15.561Z"}