remix-run/react-router · error · Error
Unable to define routes with duplicate route id: "${id}"
Error message
Unable to define routes with duplicate route id: "${id}" What it means
Thrown by configRoutesToRouteManifest() while walking the route config tree when a route's computed id already exists in routeManifest. The id is route.id if provided, otherwise createRouteId(route.file) (the file path with extension stripped and path normalized). Because flatRoutes() derives ids from file paths, two route files resolving to the same normalized id, an explicit duplicate route.id, or two routes pointing at the same file all collide.
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 1fd704a7da)
Solutions
- Search routes.ts and your app/routes for the quoted id in the error; remove or rename the duplicate entry.
- If using flatRoutes(), check for two files that normalize to the same id (e.g. parent.tsx vs parent/index.tsx) and rename one.
- Give each manual route a unique id, or omit id entirely so it derives from file.
- Ensure each route() helper call references a distinct file.
- Run the build with a clean routes.ts (comment out halves) to bisect which pair collides.
Example fix
// before (routes.ts) -- duplicate id
export default [
route('about', './about.tsx', { id: 'page' }),
route('contact', './contact.tsx', { id: 'page' }),
];
// after -- unique ids (or omit id)
export default [
route('about', './about.tsx'),
route('contact', './contact.tsx'),
]; Defensive patterns
Strategy: validation
Validate before calling
// Walk routes.ts and detect duplicate ids before build
function findDuplicateRouteIds(routes: any[]): string[] {
const ids = new Set<string>();
const dupes: string[] = [];
function walk(r: any) {
const id = r.id ?? r.file.replace(/\.[tj]sx?$/, '');
if (ids.has(id)) dupes.push(id); else ids.add(id);
(r.children ?? []).forEach(walk);
}
routes.forEach(walk);
return dupes;
}
const dupes = findDuplicateRouteIds(myRoutes);
if (dupes.length) throw new Error('Duplicate route ids: ' + dupes.join(', ')); Type guard
function hasUniqueRouteIds(routes: any[]): boolean {
const seen = new Set<string>();
for (const r of routes) {
const id = r.id ?? r.file.replace(/\.[tj]sx?$/, '');
if (seen.has(id)) return false;
seen.add(id);
}
return true;
} Prevention
- Use flatRoutes() consistently to let ids derive from file paths deterministically.
- When writing manual route() entries, omit id unless you need it, and never reuse one.
- After renaming a route file, search routes.ts for stale references.
- Add a pre-build check that asserts all route ids are unique.
When it happens
Trigger: Defining two routes with the same id via route({ id: 'x', ... }); two route files whose paths normalize identically (e.g. routes/players.tsx and routes/players/index.tsx both collapsing to the same id); manually duplicating an entry in routes.ts that points at the same file; using route() and index() helpers against the same file.
Common situations: Hand-writing routes.ts and reusing an id; file-system routing edge case where a layout and a child produce the same id; refactoring that moved a route file without updating routes.ts leaving a stale duplicate; case-insensitive filesystem masking two paths that normalize differently.
Related errors
- React Router presets must have a `name` property defined.
- Could not find package.json in ${rootDirectory} or any of it
- React Router Vite plugin not found in Vite config
- Could not resolve module ID for ${url}
- The React Router Vite plugin requires the use of a Vite conf
AI-assisted analysis of remix-run/react-router@1fd704a7da (2026-08-12).
Data as JSON: /api/errors/595bf93b7ef86421.
Report an issue: GitHub.