{"record":{"id":"59d1082cad729f38","repo":"clockworklabs/SpacetimeDB","slug":"route-conflict-for-path-59d108","errorCode":null,"errorMessage":"Route conflict for `{path}`","messagePattern":"Route conflict for `(.+?)`","errorType":"exception","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"crates/bindings-csharp/Runtime/Router.cs","lineNumber":109,"sourceCode":"        return new Router(merged);\n    }\n\n    private List<RouteSpec> CloneRoutes() => [.. routes];\n\n    private static void AddRoute(\n        List<RouteSpec> routes,\n        MethodOrAny method,\n        string path,\n        string handlerFunction\n    )\n    {\n        AssertValidPath(path);\n        ArgumentException.ThrowIfNullOrEmpty(handlerFunction);\n\n        var candidate = new RouteSpec(method, path, handlerFunction);\n        if (routes.Exists(route => RoutesOverlap(route, candidate)))\n        {\n            throw new ArgumentException($\"Route conflict for `{path}`\", nameof(path));\n        }\n\n        routes.Add(candidate);\n    }\n\n    private static string JoinPaths(string prefix, string suffix)\n    {\n        if (prefix == \"/\")\n        {\n            return suffix;\n        }\n        if (suffix == \"/\")\n        {\n            return prefix;\n        }\n\n        prefix = prefix.TrimEnd('/');\n        suffix = suffix.TrimStart('/');","sourceCodeStart":91,"sourceCodeEnd":127,"githubUrl":"https://github.com/clockworklabs/SpacetimeDB/blob/524b4487d949b61a07d4f39c862d1290259dfd20/crates/bindings-csharp/Runtime/Router.cs#L91-L127","documentation":"AddRoute throws ArgumentException when the candidate route's path is byte-equal to an existing route's path AND the methods overlap: same method on both, or either side registered with Any (Any matches all methods). Different methods on the same path are legal. Because Router methods accumulate routes via CloneRoutes, every Get/Post/... call on a chain re-checks against everything registered before it.","triggerScenarios":"Registering Get(\"/x\") twice on the same chain; Any(\"/x\") followed by Post(\"/x\") (or the reverse); a Nest whose joined sub-router path equals an already-registered path with an overlapping method; Merge of two routers that share a method+path pair.","commonSituations":"Copy-pasted route registrations; route tables assembled from multiple modules that both define '/health' or '/metrics'; mixing an Any catch-all with explicit routes on the same path.","solutions":["Find and remove the duplicate registration (the exception's path names the offending route)","If the second registration was meant for a different method, keep it — only same-method or Any overlaps conflict; drop the Any and use explicit methods","Deduplicate shared routes when merging routers assembled from separate modules"],"exampleFix":"// before\nvar router = Router.New()\n    .Get(\"/users\", listUsers)\n    .Any(\"/users\", handleUsers); // Any overlaps the Get above\n\n// after\nvar router = Router.New()\n    .Get(\"/users\", listUsers)\n    .Post(\"/users\", createUser); // different method: no conflict","handlingStrategy":"validation","validationCode":"// Keep (method, path) pairs you have registered and reject duplicates before calling the Router:\nbool IsRegistered(HashSet<(string Method, string Path)> seen, string m, string p) => seen.Contains((m, p)) || seen.Contains((\"ANY\", p)) || (m == \"ANY\" && seen.Any(k => k.Path == p));","typeGuard":null,"tryCatchPattern":"try { router = router.Get(path, handler); }\ncatch (ArgumentException e) when (e.Message.StartsWith(\"Route conflict\"))\n{ /* duplicate method+path (or Any overlap): remove or rename the route */ }","preventionTips":["Assemble routes in one place so duplicates are obvious","Prefer explicit methods over Any when the same path serves multiple methods","Add a startup unit test that just constructs the final Router"],"tags":["routing","duplicate-route","csharp"],"backgroundTag":"duplicate-route-conflict","analyzedSha":"524b4487d949b61a07d4f39c862d1290259dfd20","analyzedAt":"2026-08-16T23:58:54.611Z","schemaVersion":2},"datasetVersion":"2026-08-17T04:17:16.089Z"}