{"record":{"id":"abe886a67b87265f","repo":"clockworklabs/SpacetimeDB","slug":"cannot-nest-router-at-path-existing-routes-ov","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":"ArgumentException","httpStatus":null,"severity":"error","filePath":"crates/bindings-csharp/Runtime/Router.cs","lineNumber":58,"sourceCode":"\n    public Router Delete(string path, Handler handler) =>\n        AddRoute(new MethodOrAny.Method(new Internal.HttpMethod.Delete(default)), path, handler);\n\n    public Router Post(string path, Handler handler) =>\n        AddRoute(new MethodOrAny.Method(new Internal.HttpMethod.Post(default)), path, handler);\n\n    public Router Patch(string path, Handler handler) =>\n        AddRoute(new MethodOrAny.Method(new Internal.HttpMethod.Patch(default)), path, handler);\n\n    public Router Any(string path, Handler handler) =>\n        AddRoute(new MethodOrAny.Any(default), path, handler);\n\n    public Router Nest(string path, Router subRouter)\n    {\n        AssertValidPath(path);\n        if (routes.Exists(route => route.Path.StartsWith(path, StringComparison.Ordinal)))\n        {\n            throw new ArgumentException(\n                $\"Cannot nest router at `{path}`; existing routes overlap with nested path\",\n                nameof(path)\n            );\n        }\n\n        var merged = CloneRoutes();\n        foreach (var route in subRouter.routes)\n        {\n            var nestedPath = JoinPaths(path, route.Path);\n            AddRoute(merged, route.Method, nestedPath, route.HandlerFunction);\n        }\n\n        return new Router(merged);\n    }\n\n    public Router Merge(Router otherRouter)\n    {\n        var merged = CloneRoutes();","sourceCodeStart":40,"sourceCodeEnd":76,"githubUrl":"https://github.com/clockworklabs/SpacetimeDB/blob/6dee26c6efc2856793e12b148a59742964f5d783/crates/bindings-csharp/Runtime/Router.cs#L40-L76","documentation":"Router.Nest(path, subRouter) merges a sub-router under a prefix, but first checks that NO already-registered route path starts with the nest prefix (ordinal string StartsWith). If any existing route lies under (or equals) the prefix, it throws this ArgumentException. Note the check is a plain string prefix test, so Nest(\"/\", sub) conflicts with every existing route, and Nest after registering overlapping paths always fails — routers are immutable, registration order matters.","triggerScenarios":"Calling router.Get(\"/api/users\", h).Nest(\"/api\", sub) — /api/users starts with /api; or Nest(\"/\", sub) once the router has any route at all; or nesting two sub-routers whose prefixes overlap.","commonSituations":"Composing routers from feature modules where a feature already registered routes under the prefix later used for nesting; adding a catch-all root nest at the end of setup instead of the beginning; refactoring flat routes into nested routers without removing the originals.","solutions":["Nest BEFORE registering any routes under that prefix: Router.New().Nest(\"/api\", sub).Get(\"/users\", h)","Pick a fresh prefix that no existing route starts with","Remove the now-duplicated flat routes that the sub-router provides","Remember Nest(\"/\", ...) can only be the very first operation on an empty router"],"exampleFix":"// before - flat route already occupies the /api namespace\nvar router = Router.New()\n    .Get(\"/api/users\", listUsers)         // registered first\n    .Nest(\"/api\", apiSubRouter);           // throws: /api/users starts with /api\n\n// after - nest first, then non-overlapping routes\nvar router = Router.New()\n    .Nest(\"/api\", apiSubRouter)            // router is still empty here\n    .Get(\"/users\", listUsers);","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try { return router.Nest(prefix, subRouter); }\ncatch (ArgumentException ae) when (ae.ParamName == \"path\" && ae.Message.Contains(\"overlap\"))\n{\n    // registration-order bug: nest earlier or choose a free prefix;\n    // fail loudly in dev so route tables get fixed, don't silently drop the sub-router\n    throw new InvalidOperationException($\"Route setup order invalid for nest at {prefix}\", ae);\n}","preventionTips":["Compose routers with Nest first, leaf routes after","Treat '/' nesting as the first call on an empty router only","Build the full route table in one function so ordering is visible in review"],"tags":["csharp","router","http","route-conflict"],"backgroundTag":"route-registration-conflict","analyzedSha":"6dee26c6efc2856793e12b148a59742964f5d783","analyzedAt":"2026-08-20T06:08:37.179Z","contentChangedAt":"2026-08-20T06:08:37.179Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}