clockworklabs/SpacetimeDB · error · ArgumentException
Cannot nest router at `{path}`; existing routes overlap with
Error message
Cannot nest router at `{path}`; existing routes overlap with nested path What it means
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'.
Source
Thrown at crates/bindings-csharp/Runtime/Router.cs:58
public Router Delete(string path, Handler handler) =>
AddRoute(new MethodOrAny.Method(new Internal.HttpMethod.Delete(default)), path, handler);
public Router Post(string path, Handler handler) =>
AddRoute(new MethodOrAny.Method(new Internal.HttpMethod.Post(default)), path, handler);
public Router Patch(string path, Handler handler) =>
AddRoute(new MethodOrAny.Method(new Internal.HttpMethod.Patch(default)), path, handler);
public Router Any(string path, Handler handler) =>
AddRoute(new MethodOrAny.Any(default), path, handler);
public Router Nest(string path, Router subRouter)
{
AssertValidPath(path);
if (routes.Exists(route => route.Path.StartsWith(path, StringComparison.Ordinal)))
{
throw new ArgumentException(
$"Cannot nest router at `{path}`; existing routes overlap with nested path",
nameof(path)
);
}
var merged = CloneRoutes();
foreach (var route in subRouter.routes)
{
var nestedPath = JoinPaths(path, route.Path);
AddRoute(merged, route.Method, nestedPath, route.HandlerFunction);
}
return new Router(merged);
}
public Router Merge(Router otherRouter)
{
var merged = CloneRoutes();View on GitHub (pinned to 524b4487d9)
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
Example fix
// before
var router = Router.New()
.Get("/users", listUsers) // blocks the nest below
.Nest("/users", userRouter);
// after
var router = Router.New()
.Nest("/users", userRouter) // nest first
.Get("/health", health); // register only non-overlapping prefixes after Defensive patterns
Strategy: validation
Validate before calling
// Track the paths you registered, then check before nesting:
bool SafeToNest(HashSet<string> registered, string prefix) =>
!registered.Any(p => p.StartsWith(prefix, StringComparison.Ordinal)); Try / catch
try { router = router.Nest(prefix, sub); }
catch (ArgumentException e) when (e.Message.Contains("overlap with nested path"))
{ /* restructure: nest first or pick a disjoint prefix */ } Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Cannot nest router at `${path}`; existing routes overlap wit
- Route conflict for `${path}`
- Unrecognized extra bytes while decoding BSATN value
- Invalid HTTP method returned from host
- Invalid HTTP version returned from host
AI-assisted analysis of clockworklabs/SpacetimeDB@524b4487d9 (2026-08-16).
Data as JSON: /api/errors/abe886a67b87265f.
Report an issue: GitHub.