remix-run/react-router · error · Error
Custom Vite manifest paths are not supported
Error message
Custom Vite manifest paths are not supported
What it means
Thrown in `resolveViteConfig` after Vite resolves the user config. React Router writes its build manifest to a fixed, well-known path inside the build directory and reads it back during SSR/preview, so a user-supplied `build.manifest` string (Vite's option for naming `manifest.json`) would relocate Vite's own manifest and break React Router's lookups. Only `build.manifest === true` (or unset) is compatible.
Source
Thrown at packages/react-router-dev/vite/plugin.ts:126
root,
plugins,
}: {
configFile?: string;
mode?: string;
plugins?: Vite.Plugin[];
root: string;
}) {
let vite = getVite();
let viteConfig = await vite.resolveConfig(
{ mode, configFile, root, plugins },
"build", // command
"production", // default mode
"production", // default NODE_ENV
);
if (typeof viteConfig.build.manifest === "string") {
throw new Error("Custom Vite manifest paths are not supported");
}
return viteConfig;
}
export function extractPluginContext(
viteConfig: Vite.ResolvedConfig | Vite.UserConfig,
) {
return viteConfig["__reactRouterPluginContext" as keyof typeof viteConfig] as
| ReactRouterPluginContext
| undefined;
}
const SERVER_ONLY_ROUTE_EXPORTS = ["loader", "action", "middleware", "headers"];
const CLIENT_NON_COMPONENT_EXPORTS = [
"clientAction",
"clientLoader",
"clientMiddleware",View on GitHub (pinned to 1fd704a7da)
Solutions
- Remove the custom string from `build.manifest` in `vite.config.ts`; leave it unset or set it to `true`.
- If you need a specific manifest name for a downstream tool, post-process the built file with a script after `react-router build` instead of using Vite's option.
- Search the repo for `manifest:` to catch a stale override.
Example fix
// before
export default defineConfig({
plugins: [reactRouter()],
build: { manifest: "my-manifest.json" },
});
// after
export default defineConfig({
plugins: [reactRouter()],
build: { manifest: true },
}); Defensive patterns
Strategy: validation
Validate before calling
import type { UserConfig } from "vite";
const assertNoCustomManifest = (cfg: UserConfig) => {
if (typeof cfg.build?.manifest === "string") {
throw new Error("build.manifest must be boolean, not a custom string");
}
}; Type guard
const isManifestSafe = (m: unknown): boolean => m === undefined || m === true || m === false;
Prevention
- Never set `build.manifest` to a string in React Router projects.
- Audit `vite.config.ts` after copying config from non-React-Router templates.
- Prefer leaving `build.manifest` unset — React Router manages it.
When it happens
Trigger: User sets `build.manifest: "custom-name.json"` (a string) in `vite.config.ts`; or copies a Vue/legacy config that used a custom manifest filename; or sets `build.manifest` conditionally to a string in production.
Common situations: Migrating from a hand-rolled Vite SPA setup that pinned `manifest.json` to a specific name; copy-pasting config from a non-React-Router tutorial; enabling Vite's manifest feature with a custom name thinking React Router respects it.
Related errors
- React Router Vite plugin not found in Vite config
- The "serverBundles" function must return a string
- Unable to prerender path because it does not match any route
- The React Router Vite plugin requires the use of a Vite conf
- The "serverBundles" function must only return strings contai
AI-assisted analysis of remix-run/react-router@1fd704a7da (2026-08-12).
Data as JSON: /api/errors/1255f066a5c50266.
Report an issue: GitHub.