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

When React Router resolves the Vite config for its child compilers, it checks `viteConfig.build.manifest`. The framework reads the Vite manifest from its well-known default location to map route modules to built assets, so a custom manifest path string is rejected outright. This is a compatibility guard: RR post-processes the manifest itself and cannot follow a relocated one.

Solutions

  1. Remove the custom string from `build.manifest` in vite.config.ts and let it stay `true`/unset so Vite emits `.vite/manifest.json` at the default path
  2. If you need the manifest for another tool, read it from `build/assets/.vite/manifest.json` after the build instead of relocating it
  3. Scope any custom Vite build config used by other apps away from the React Router app's vite.config.ts

Example fix

// before (vite.config.ts)
export default defineConfig({
  build: { manifest: 'dist/rr-manifest.json' },
});

// after
export default defineConfig({
  build: { manifest: true }, // default .vite/manifest.json location
});
Defensive patterns

Strategy: validation

Validate before calling

// Pre-flight check before running react-router build
import type { UserConfig } from 'vite';
const cfg: UserConfig = { /* ... */ };
if (typeof cfg.build?.manifest === 'string') {
  throw new Error('React Router does not support a custom build.manifest path');
}
export default cfg;

Type guard

const hasCustomManifestPath = (cfg: { build?: { manifest?: unknown } }): boolean =>
  typeof cfg.build?.manifest === 'string';

Try / catch

try {
  await build();
} catch (e) {
  if (e instanceof Error && e.message.includes('manifest paths are not supported')) {
    console.error('Remove build.manifest path from vite.config.ts and retry');
    process.exit(1);
  }
  throw e;
}

Prevention

When it happens

Trigger: Setting `build.manifest: 'custom/manifest.json'` (any string) in vite.config.ts while the React Router Vite plugin is active; copying a shared Vite config from a non-React Router project that customizes the manifest path; enabling `build.manifest` with a path via a shared config preset.

Common situations: Teams reusing an existing Vite config that set `build.manifest` for their own asset pipeline; CI configs that centralized `manifest: 'dist/manifest.json'`; upgrading to Framework Mode while keeping legacy Vite build options.

Related errors


AI-assisted analysis of remix-run/react-router@6beaca3952 (2026-08-18). Data as JSON: /api/errors/1255f066a5c50266. Report an issue: GitHub.

Appendix: 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 6beaca3952)