remix-run/react-router · error · Error
The "serverBundles" function must return a string
Error message
The "serverBundles" function must return a string
What it means
Thrown while building the server-bundle manifest. The user-supplied `serverBundles({ branch })` config function must return a string ID naming the bundle the route branch belongs to. A non-string return (undefined, number, object, Promise of non-string) breaks manifest construction because the ID is used as a Vite environment name and a manifest key.
Source
Thrown at packages/react-router-dev/vite/plugin.ts:3465
serverBundles: {},
routeIdToServerBundleId: {},
routes: rootRelativeRoutes,
};
await Promise.all(
getAddressableRoutes(routes).map(async (route) => {
let branch = getRouteBranch(routes, route.id);
let serverBundleId = await serverBundles({
branch: branch.map((route) =>
configRouteToBranchRoute({
...route,
// Ensure absolute paths are passed to the serverBundles function
file: path.join(resolvedAppDirectory, route.file),
}),
),
});
if (typeof serverBundleId !== "string") {
throw new Error(`The "serverBundles" function must return a string`);
}
// Server bundle IDs must be valid Vite environment names, so hyphens are not allowed
if (!/^[a-zA-Z0-9_]+$/.test(serverBundleId)) {
throw new Error(
`The "serverBundles" function must only return strings containing alphanumeric characters and underscores.`,
);
}
buildManifest.routeIdToServerBundleId[route.id] = serverBundleId;
buildManifest.serverBundles[serverBundleId] ??= {
id: serverBundleId,
file: normalizePath(
path.join(
path.relative(
rootDirectory,
path.join(serverBuildDirectory, serverBundleId),
),
reactRouterConfig.serverBuildFile,View on GitHub (pinned to 1fd704a7da)
Solutions
- Ensure every code path in `serverBundles` returns a string.
- Add a default return at the end (e.g. `return "root";`).
- Annotate the function's return type as `Promise<string> | string` so TypeScript flags missing returns.
- Unit-test the function over all branches before running the full build.
Example fix
// before
export const serverBundles = async ({ branch }) => {
if (branch.some(r => r.id === "admin")) "admin"; // forgot return
};
// after
export const serverBundles = async ({ branch }): Promise<string> => {
if (branch.some(r => r.id === "admin")) return "admin";
return "root";
}; Defensive patterns
Strategy: type-guard
Type guard
const isServerBundleId = (v: unknown): v is string => typeof v === "string" && v.length > 0;
Prevention
- Annotate `serverBundles` with an explicit `Promise<string>` return type so the compiler catches missing returns.
- Add a default `return "root";` at the end of the function.
- Unit-test the function over representative branches.
When it happens
Trigger: A `serverBundles` function that forgets to `return` (implicitly returns `undefined`); returns a number/object; an async function whose awaited value is not a string; branching logic that returns nothing on some paths.
Common situations: Authoring `serverBundles` for the first time; refactoring the function and dropping a return; early-return guard clauses that miss a branch.
Related errors
- Custom Vite manifest paths are not supported
- The "serverBundles" function must only return strings contai
- Unable to prerender path because it does not match any route
- React Router Vite plugin not found in Vite config
- Could not parse TypeScript
AI-assisted analysis of remix-run/react-router@1fd704a7da (2026-08-12).
Data as JSON: /api/errors/8d7b2a0349fc8827.
Report an issue: GitHub.