remix-run/react-router · error
The `routeDiscovery.manifestPath` config must be a root-rela
Error message
The `routeDiscovery.manifestPath` config must be a root-relative pathname beginning with a slash (i.e., "/__manifest")
What it means
With lazy route discovery, the client fetches route manifests from `manifestPath` (default `/__manifest`). The value must be a root-relative pathname starting with `/`; anything else — `__manifest`, `manifest.json`, `https://cdn.example.com/__manifest` — fails the `startsWith("/")` check when `manifestPath` is explicitly set alongside `mode: "lazy"`.
Source
Thrown at packages/react-router-dev/config/config.ts:606
routeDiscovery = {
mode: "lazy",
manifestPath: "/__manifest",
};
} else {
routeDiscovery = { mode: "initial" };
}
} else if (userRouteDiscovery.mode === "initial") {
routeDiscovery = userRouteDiscovery;
} else if (userRouteDiscovery.mode === "lazy") {
if (!ssr) {
return err(
'The `routeDiscovery.mode` config cannot be set to "lazy" when setting `ssr:false`',
);
}
let { manifestPath } = userRouteDiscovery;
if (manifestPath != null && !manifestPath.startsWith("/")) {
return err(
"The `routeDiscovery.manifestPath` config must be a root-relative " +
'pathname beginning with a slash (i.e., "/__manifest")',
);
}
routeDiscovery = userRouteDiscovery;
}
let appDirectory = Path.resolve(root, userAppDirectory || "app");
let buildDirectory = Path.resolve(root, userBuildDirectory);
let rootRouteFile = findEntry(appDirectory, "root", { absolute: true });
if (!rootRouteFile) {
let rootRouteDisplayPath = Path.relative(
root,
Path.join(appDirectory, "root.tsx"),
);
return err(View on GitHub (pinned to 6beaca3952)
Solutions
- Prefix the path with a slash: `manifestPath: "/__manifest"` or your custom `/api/manifest`.
- Omit `manifestPath` to use the default `/__manifest`.
- If you need the manifest elsewhere, remember it is served by your app's origin — keep it root-relative.
Example fix
// before
export default {
routeDiscovery: { mode: "lazy", manifestPath: "__manifest" },
};
// after
export default {
routeDiscovery: { mode: "lazy", manifestPath: "/__manifest" },
}; Defensive patterns
Strategy: validation
Validate before calling
function isRootRelative(p: string): boolean {
return p.startsWith("/");
}
if (manifestPath != null && !isRootRelative(manifestPath)) {
throw new Error("routeDiscovery.manifestPath must start with '/'");
} Type guard
function isRootRelativePathname(p: string): p is `/${string}` {
return p.startsWith("/") && !/^\/\//.test(p);
} Prevention
- Omit manifestPath unless you genuinely need a custom endpoint path.
- Store custom endpoint paths with the leading slash in one constants module.
- Never put an absolute URL or bare filename in this field.
When it happens
Trigger: Explicitly configuring `routeDiscovery: { mode: "lazy", manifestPath: "__manifest" }` (missing leading slash) or an absolute URL; the check only runs for non-null values with lazy mode, so `undefined` keeps the default.
Common situations: Customizing the manifest path to avoid conflicts with an existing `/__manifest` route; copying a path constant that is stored without the leading slash; intending a CDN host and putting the full URL in this field (not supported — it is server-relative).
Understand the failure class
Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.
Related errors
- The `routeDiscovery.mode` config cannot be set to "lazy" whe
- React Router presets must have a `name` property defined.
- onChange is not supported when watch mode is disabled
- Could not find package.json in ${rootDirectory} or any of it
- React Router Vite plugin not found in Vite config
AI-assisted analysis of remix-run/react-router@6beaca3952 (2026-08-18).
Data as JSON: /api/errors/7c45ed08000ae379.
Report an issue: GitHub.