{"record":{"id":"241e22af477e5c29","repo":"nestjs/nest","slug":"conflicting-http-routes-detected-messages","errorCode":null,"errorMessage":"Conflicting HTTP routes detected:\n  - ${messages}\nAdjust route declarations or relax the 'routeConflictPolicy' option passed to NestFactory.create() to allow the application to start.","messagePattern":"Conflicting HTTP routes detected:\n  - (.+?)\nAdjust route declarations or relax the 'routeConflictPolicy' option passed to NestFactory\\.create\\(\\) to allow the application to start\\.","errorType":"exception","errorClass":"RouteConflictException","httpStatus":null,"severity":"critical","filePath":"packages/core/router/route-conflict-detector.ts","lineNumber":201,"sourceCode":"    if (conflicts.length === 0 || policy === undefined) return;\n\n    const errorMessages: string[] = [];\n\n    conflicts.forEach(conflict => {\n      const policyForKind = policy[conflict.kind] ?? 'off';\n      if (policyForKind === 'off') return;\n\n      const message = RouteConflictDetector.describeConflict(conflict);\n\n      if (policyForKind === 'warn') {\n        logger.warn(message);\n        return;\n      }\n      errorMessages.push(message);\n    });\n\n    if (errorMessages.length > 0) {\n      throw new RouteConflictException(errorMessages);\n    }\n  }\n\n  /**\n   * Removes shadow conflicts that specificity sorting has already resolved.\n   *\n   * When `routeResolutionStrategy: 'specificity'` is active, the sort\n   * promotes more-specific routes ahead of less-specific ones. A shadow\n   * where the sort promoted the winner (it was declared *later* but sorted\n   * *first*) is handled correctly at runtime — the more-specific route is\n   * registered first and handles its requests while the less-specific route\n   * handles the rest. Retaining such a conflict would cause `shadow: 'error'`\n   * to abort an application whose routes actually work as intended.\n   *\n   * Shadows where the winner was already first in declaration order (the\n   * sort did not swap them) are genuine and are kept unchanged. Duplicate\n   * conflicts are always kept.\n   *","sourceCodeStart":183,"sourceCodeEnd":219,"githubUrl":"https://github.com/nestjs/nest/blob/dd75d7bd8c5e88048587e6768d36eb695f3e7a25/packages/core/router/route-conflict-detector.ts#L183-L219","documentation":"At bootstrap the route conflict detector classifies every pair of registered routes (duplicates, version conflicts, shadowing under the 'specificity' strategy) and applies the `routeConflictPolicy` option per conflict kind ('error' | 'warn' | 'off'; duplicates default to 'error'). When at least one conflict resolves to 'error', RouteConflictException is thrown listing every conflicting route so the app refuses to start with ambiguous routing.","triggerScenarios":"Two controllers (or repeated registrations of the same controller in modules) map the same method+path, e.g. `@Get('users')` under both a global-prefix-less and prefixed controller; a versioned route (URI versioning `v1/users`) colliding with a static segment; shadow conflicts where a less specific route would never match because a more specific one is declared first — with shadow policy set to 'error'; platform version upgrades where path-to-regexp pattern semantics changed and previously distinct routes now overlap.","commonSituations":"Adding a new controller whose paths unintentionally duplicate an existing one; registering the same controller in two modules; enabling URI versioning on legacy routes; adopting NestJS 11 where duplicate detection became strict; micro-frontends merging routers.","solutions":["Disambiguate the routes: give controllers distinct `@Controller('prefix')` paths or change methods so no two handlers claim the same method+path.","If the duplicate is intentional (e.g., one route overriding another), relax the policy: `NestFactory.create(AppModule, { routeConflictPolicy: { duplicate: 'warn' } })`.","When using `routeResolutionStrategy: 'specificity'`, verify shadow policies match your intent (`shadow: 'warn'`) or restructure paths so shadowing disappears.","Run `app.init()` in CI to catch conflicts before deploy even if you relax runtime behavior."],"exampleFix":"// before\n@Controller('users') export class AdminUsersController { @Get() findAll() {} }\n@Controller('users') export class PublicUsersController { @Get() findAll() {} } // duplicate -> error\n\n// after\n@Controller('admin/users') export class AdminUsersController { @Get() findAll() {} }\n@Controller('users')   export class PublicUsersController { @Get() findAll() {} }\n\n// or, if overlap is intended:\nconst app = await NestFactory.create(AppModule, {\n  routeConflictPolicy: { duplicate: 'warn' },\n});","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"// CI-friendly: surface every conflict route pair, then fail\ntry {\n  const app = await NestFactory.create(AppModule);\n  await app.init(); // runs conflict detection\n} catch (e: any) {\n  if (e?.name === 'RouteConflictException' || /Conflicting HTTP routes/i.test(e?.message)) {\n    console.error(e.message); // lists each conflicting route\n    process.exit(1);\n  }\n  throw e;\n}","preventionTips":["Give controllers unique path prefixes and never register the same controller in two modules.","Run app.init() in CI so route conflicts block merges before deploy.","Set routeConflictPolicy explicitly per conflict kind rather than relying on defaults across upgrades.","Generate an OpenAPI snapshot in CI — new unexpected paths surface overlaps early."],"tags":["routing","route-conflict","bootstrap","http"],"backgroundTag":"duplicate-route-registration","analyzedSha":"dd75d7bd8c5e88048587e6768d36eb695f3e7a25","analyzedAt":"2026-08-21T19:39:39.867Z","contentChangedAt":"2026-08-21T19:39:39.867Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}