remix-run/react-router · error · Error
Unable to define routes with duplicate route id
Error message
Unable to define routes with duplicate route id: "${id}" What it means
configRoutesToRouteManifest() assigns each route an id — explicitly via route.id, otherwise the file path with its extension stripped and normalized (createRouteId). Before inserting into the manifest it checks for an existing entry with the same id and throws on the first duplicate, because the manifest is keyed by id and ambiguity would break route generation. In Framework Mode this surfaces while processing routes.ts (flatRoutes output or manual config).
Solutions
- Give one of the colliding routes an explicit unique id: route("a", "./x.tsx", { id: "x-a" })
- If two files collide (differing extensions or case), delete or rename one of them
- Search your routes config / app/routes files for the id quoted in the message to locate both definitions
Example fix
// before: same file twice -> duplicate id "routes/layout"
import type { RouteConfig } from "@react-router/dev/routes";
export default [
route("a", "./layout.tsx", [index("./a.tsx")]),
route("b", "./layout.tsx", [index("./b.tsx")]),
] satisfies RouteConfig;
// after: explicit unique ids
export default [
route("a", "./layout.tsx", { id: "layout-a" }, [index("./a.tsx")]),
route("b", "./layout.tsx", { id: "layout-b" }, [index("./b.tsx")]),
] satisfies RouteConfig; Defensive patterns
Strategy: validation
Validate before calling
import type { RouteConfig } from "@react-router/dev/routes";
function assertUniqueRouteIds(routes: RouteConfig): void {
const seen = new Set<string>();
const walk = (route: RouteConfig[number]): void => {
const id = route.id ?? route.file.replace(/\.[a-z0-9]+$/i, "");
if (seen.has(id)) throw new Error(`Duplicate route id: "${id}" (from ${route.file})`);
seen.add(id);
route.children?.forEach(walk);
};
routes.forEach(walk);
}
const config = flatRoutes() satisfies RouteConfig;
assertUniqueRouteIds(config);
export default config; Type guard
function isRouteConfigEntry(v: unknown): v is { id?: string; file: string; children?: unknown[] } {
return typeof v === "object" && v !== null && typeof (v as { file?: unknown }).file === "string";
} Prevention
- When reusing one file for multiple routes, always pass distinct explicit { id: "..." } options
- Avoid route filenames that differ only by extension or letter case
- Run configRoutesToRouteManifest (or the assert above) in a CI check to catch duplicates before build
When it happens
Trigger: Referencing the same file from two route() calls (e.g. a shared layout used at two paths) without distinct explicit ids; two route files differing only by extension (routes.ts and routes.tsx) or by case on case-insensitive filesystems; duplicate explicit id values; flatRoutes configs where filenames collide after extension stripping.
Common situations: Reusing one component file for multiple routes during refactors; macOS/Windows development hiding case-only duplicates that explode on Linux CI; renames that leave both old and new entries in the config.
Related errors
- Route config file not found at
- Could not find a root route module in the app directory as
- Could not find package.json in
- React Router presets must have a `name` property defined.
- Route config in " " is invalid.
AI-assisted analysis of remix-run/react-router@6beaca3952 (2026-08-18).
Data as JSON: /api/errors/595bf93b7ef86421.
Report an issue: GitHub.
Appendix: source
Thrown at packages/react-router-dev/config/routes.ts:377
routes: RouteConfigEntry[],
): RouteManifest {
let routeManifest: RouteManifest = {};
function walk(route: RouteConfigEntry, parentId?: string) {
let id = route.id || createRouteId(route.file);
let manifestItem: RouteManifestEntry = {
id,
parentId,
file: Path.isAbsolute(route.file)
? Path.relative(appDirectory, route.file)
: route.file,
path: route.path,
index: route.index,
caseSensitive: route.caseSensitive,
};
if (routeManifest.hasOwnProperty(id)) {
throw new Error(
`Unable to define routes with duplicate route id: "${id}"`,
);
}
routeManifest[id] = manifestItem;
if (route.children) {
for (let child of route.children) {
walk(child, id);
}
}
}
for (let route of routes) {
walk(route);
}
return routeManifest;
}View on GitHub (pinned to 6beaca3952)