{"record":{"id":"7dda002fd9a2ddb5","repo":"clockworklabs/SpacetimeDB","slug":"cannot-nest-router-at-path-existing-routes-o","errorCode":null,"errorMessage":"Cannot nest router at `${path}`; existing routes overlap with nested path","messagePattern":"Cannot nest router at `(.+?)`; existing routes overlap with nested path","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"crates/bindings-typescript/src/server/http_handlers.ts","lineNumber":320,"sourceCode":"    );\n  }\n\n  patch(path: string, handler: HttpHandlerExport<any>) {\n    return this.addRoute(\n      { tag: 'Method', value: { tag: 'Patch' } },\n      path,\n      handler\n    );\n  }\n\n  any(path: string, handler: HttpHandlerExport<any>) {\n    return this.addRoute({ tag: 'Any' }, path, handler);\n  }\n\n  nest(path: string, subRouter: Router) {\n    assertValidPath(path);\n    if (this.#routes.some(route => route.path.startsWith(path))) {\n      throw new TypeError(\n        `Cannot nest router at \\`${path}\\`; existing routes overlap with nested path`\n      );\n    }\n    let merged = new Router(this.#routes);\n    for (const route of subRouter.#routes) {\n      merged = merged.addRoute(\n        route.method,\n        joinPaths(path, route.path),\n        route.handler\n      );\n    }\n    return merged;\n  }\n\n  merge(otherRouter: Router) {\n    let merged = new Router(this.#routes);\n    for (const route of otherRouter.#routes) {\n      merged = merged.addRoute(route.method, route.path, route.handler);","sourceCodeStart":302,"sourceCodeEnd":338,"githubUrl":"https://github.com/clockworklabs/SpacetimeDB/blob/524b4487d949b61a07d4f39c862d1290259dfd20/crates/bindings-typescript/src/server/http_handlers.ts#L302-L338","documentation":"Router.nest(path, subRouter) mounts a sub-router's routes under path. Before merging, it checks that no already-registered route path starts with the nest path, because the merged sub-routes would collide with those existing routes. If any current route has the nest path as a prefix, nest throws a TypeError.","triggerScenarios":"Calling router.get('/api/users', h) first and then router.nest('/api', subRouter): '/api/users'.startsWith('/api') is true, so nesting is refused. Also nest('', sub) conflicts with every route once any route exists.","commonSituations":"Refactoring a flat router into nested sub-routers while some old routes remain in the parent; copy-pasting setup code that registers a route under the same prefix being mounted; mounting at the root path '' after registering anything.","solutions":["Move the conflicting parent routes into the sub-router (or delete them) before nesting","Nest first, then register any parent-level routes that do not share the prefix","Choose a nest path that is not a prefix of any existing route, e.g. nest('/v2/api', sub) instead of '/api'"],"exampleFix":"// before\nconst router = new Router()\n  .get('/api/users', listUsers)\n  .nest('/api', apiSubRouter); // throws: '/api/users' starts with '/api'\n\n// after: overlapping routes live in the sub-router\nconst apiSubRouter = new Router().get('/users', listUsers);\nconst router = new Router().nest('/api', apiSubRouter);","handlingStrategy":"validation","validationCode":"function canNest(router: Router, path: string): boolean {\n  return !router.intoRoutes().some(r => r.path.startsWith(path));\n}\n// before mounting:\nif (!canNest(router, '/api')) throw new Error('nest would overlap existing routes');","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Structure route setup so sub-routers are nested before any parent routes under the same prefix are registered","Give each sub-router an exclusive prefix and never register parent routes under it","Cover router composition with unit tests so nesting errors fail at build time in CI"],"tags":["http","router","routing","typescript"],"backgroundTag":"route-conflict","analyzedSha":"524b4487d949b61a07d4f39c862d1290259dfd20","analyzedAt":"2026-08-16T23:58:54.611Z","schemaVersion":2},"datasetVersion":"2026-08-17T04:17:16.089Z"}