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

  1. Search routes.ts and your app/routes for the quoted id in the error; remove or rename the duplicate entry.
  2. If using flatRoutes(), check for two files that normalize to the same id (e.g. parent.tsx vs parent/index.tsx) and rename one.
  3. Give each manual route a unique id, or omit id entirely so it derives from file.
  4. Ensure each route() helper call references a distinct file.
  5. 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

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


AI-assisted analysis of remix-run/react-router@1fd704a7da (2026-08-12). Data as JSON: /api/errors/595bf93b7ef86421. Report an issue: GitHub.