clockworklabs/SpacetimeDB · error · ArgumentException
Cannot nest router at
Error message
Cannot nest router at `{path}`; existing routes overlap with nested path What it means
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.
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
Example fix
// before - flat route already occupies the /api namespace
var router = Router.New()
.Get("/api/users", listUsers) // registered first
.Nest("/api", apiSubRouter); // throws: /api/users starts with /api
// after - nest first, then non-overlapping routes
var router = Router.New()
.Nest("/api", apiSubRouter) // router is still empty here
.Get("/users", listUsers); Defensive patterns
Strategy: try-catch
Try / catch
try { return router.Nest(prefix, subRouter); }
catch (ArgumentException ae) when (ae.ParamName == "path" && ae.Message.Contains("overlap"))
{
// registration-order bug: nest earlier or choose a free prefix;
// fail loudly in dev so route tables get fixed, don't silently drop the sub-router
throw new InvalidOperationException($"Route setup order invalid for nest at {prefix}", ae);
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Route conflict for
- Cannot nest router at
- Route conflict for
- Route paths may contain only
- Route paths must start with `/
AI-assisted analysis of clockworklabs/SpacetimeDB@6dee26c6ef (2026-08-20).
Data as JSON: /api/errors/abe886a67b87265f.
Report an issue: GitHub.
Appendix: 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 6dee26c6ef)