{"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/524b4487d949b61a07d4f39c862d1290259dfd20/crates/bindings-csharp/Runtime/Router.cs#L40-L76","documentation":"Router.Nest(path, subRouter) refuses to mount a sub-router when any route already registered on the current router has a path that string-starts-with the nest prefix. Router is immutable and fluent (each Get/Post/Nest returns a new router with accumulated routes), so the check covers everything built earlier in the chain. The check is a literal StartsWith, not segment-aware, so '/users-all' also blocks nesting at '/users'.","triggerScenarios":"Calling .Get(\"/users\", h) (or any method) before .Nest(\"/users\", subRouter) on the same chain; also plain prefix collisions such as an existing '/v1' route when nesting at '/v1/admin'. Nesting at '/' conflicts with every non-empty existing path.","commonSituations":"Refactoring a flat route list into nested routers while leaving one route under the old prefix; additive route building where a catch-all or sibling route shares the prefix string; porting route tables from frameworks where nesting is resolved per-segment.","solutions":["Reorder the chain: call Nest(path, subRouter) first, then register routes that live outside the nested prefix","Choose a nest prefix that no existing route path starts with (audit the chain built so far)","Restructure: build sub-routers against Router.New() and Merge them, keeping top-level prefixes disjoint"],"exampleFix":"// before\nvar router = Router.New()\n    .Get(\"/users\", listUsers)   // blocks the nest below\n    .Nest(\"/users\", userRouter);\n\n// after\nvar router = Router.New()\n    .Nest(\"/users\", userRouter) // nest first\n    .Get(\"/health\", health);    // register only non-overlapping prefixes after","handlingStrategy":"validation","validationCode":"// Track the paths you registered, then check before nesting:\nbool SafeToNest(HashSet<string> registered, string prefix) =>\n    !registered.Any(p => p.StartsWith(prefix, StringComparison.Ordinal));","typeGuard":null,"tryCatchPattern":"try { router = router.Nest(prefix, sub); }\ncatch (ArgumentException e) when (e.Message.Contains(\"overlap with nested path\"))\n{ /* restructure: nest first or pick a disjoint prefix */ }","preventionTips":["Adopt a nest-first convention: mount all sub-routers, then add top-level routes","Keep the route table in one module and unit-test its construction at startup","Remember the overlap test is a literal string prefix, not segment-aware"],"tags":["routing","http","csharp"],"backgroundTag":"router-nesting-overlap","analyzedSha":"524b4487d949b61a07d4f39c862d1290259dfd20","analyzedAt":"2026-08-16T23:58:54.611Z","schemaVersion":2},"datasetVersion":"2026-08-17T04:17:16.089Z"}