{"record":{"id":"4860e26ac7d58958","repo":"remix-run/react-router","slug":"the-serverbundles-function-must-only-return-stri","errorCode":null,"errorMessage":"The \"serverBundles\" function must only return strings containing alphanumeric characters and underscores.","messagePattern":"The \"serverBundles\" function must only return strings containing alphanumeric characters and underscores\\.","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/react-router-dev/vite/plugin.ts","lineNumber":3469,"sourceCode":"\n  await Promise.all(\n    getAddressableRoutes(routes).map(async (route) => {\n      let branch = getRouteBranch(routes, route.id);\n      let serverBundleId = await serverBundles({\n        branch: branch.map((route) =>\n          configRouteToBranchRoute({\n            ...route,\n            // Ensure absolute paths are passed to the serverBundles function\n            file: path.join(resolvedAppDirectory, route.file),\n          }),\n        ),\n      });\n      if (typeof serverBundleId !== \"string\") {\n        throw new Error(`The \"serverBundles\" function must return a string`);\n      }\n      // Server bundle IDs must be valid Vite environment names, so hyphens are not allowed\n      if (!/^[a-zA-Z0-9_]+$/.test(serverBundleId)) {\n        throw new Error(\n          `The \"serverBundles\" function must only return strings containing alphanumeric characters and underscores.`,\n        );\n      }\n      buildManifest.routeIdToServerBundleId[route.id] = serverBundleId;\n\n      buildManifest.serverBundles[serverBundleId] ??= {\n        id: serverBundleId,\n        file: normalizePath(\n          path.join(\n            path.relative(\n              rootDirectory,\n              path.join(serverBuildDirectory, serverBundleId),\n            ),\n            reactRouterConfig.serverBuildFile,\n          ),\n        ),\n      };\n    }),","sourceCodeStart":3451,"sourceCodeEnd":3487,"githubUrl":"https://github.com/remix-run/react-router/blob/1fd704a7dabcbe3ae09d7387b460e6acaba30ec1/packages/react-router-dev/vite/plugin.ts#L3451-L3487","documentation":"Thrown immediately after the string-typed check on the same value. Server bundle IDs become Vite environment names, which disallow hyphens and other punctuation, so React Router enforces `^[a-zA-Z0-9_]+$`. A return value like `\"admin-bundle\"`, `\"v1.2\"`, or one containing slashes/spaces fails the regex and aborts the build.","triggerScenarios":"Returning a hyphenated, dotted, spaced, or otherwise punctuated bundle ID from `serverBundles`; constructing IDs dynamically from route file paths (which contain `/` and `.`); copy-pasting IDs from a naming convention that uses dashes.","commonSituations":"Naming bundles by feature with dashes (`admin-area`); using kebab-case from route file paths; internationalized IDs with non-ASCII characters.","solutions":["Use only `[A-Za-z0-9_]` in the returned ID — prefer underscores over hyphens (e.g. `admin_area`).","If deriving from paths, sanitize: `id.replace(/[^a-zA-Z0-9_]/g, \"_\")`.","Pin the function's return type to a branded `ServerBundleId` type to catch slips."],"exampleFix":"// before\nexport const serverBundles = ({ branch }) => \"admin-bundle\";\n// after\nexport const serverBundles = ({ branch }) => \"admin_bundle\";","handlingStrategy":"validation","validationCode":"const VALID = /^[a-zA-Z0-9_]+$/;\nconst assertValidBundleId = (id: string) => {\n  if (!VALID.test(id)) throw new Error(`Invalid bundle id: ${id}`);\n};","typeGuard":"const isValidBundleId = (v: unknown): v is string =>\n  typeof v === \"string\" && /^[a-zA-Z0-9_]+$/.test(v);","tryCatchPattern":null,"preventionTips":["Restrict bundle IDs to `[A-Za-z0-9_]` — use underscores, not hyphens.","If deriving IDs from paths, sanitize with `replace(/[^a-zA-Z0-9_]/g, \"_\")`.","Brand the return type so the compiler enforces the format."],"tags":["server-bundles","config","validation","build"],"backgroundTag":null,"analyzedSha":"1fd704a7dabcbe3ae09d7387b460e6acaba30ec1","analyzedAt":"2026-08-12T13:54:57.804Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}