{"record":{"id":"09c1d4e29f1258cc","repo":"clockworklabs/SpacetimeDB","slug":"route-paths-must-start-with-path-09c1d4","errorCode":null,"errorMessage":"Route paths must start with `/`: {path}","messagePattern":"Route paths must start with `/`: (.+?)","errorType":"exception","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"crates/bindings-csharp/Runtime/Router.cs","lineNumber":148,"sourceCode":"\n    private static bool RoutesOverlap(RouteSpec a, RouteSpec b)\n    {\n        if (!string.Equals(a.Path, b.Path, StringComparison.Ordinal))\n        {\n            return false;\n        }\n\n        return a.Method is MethodOrAny.Any\n            || b.Method is MethodOrAny.Any\n            || Equals(a.Method, b.Method);\n    }\n\n    private static void AssertValidPath(string path)\n    {\n        ArgumentNullException.ThrowIfNull(path);\n        if (path.Length > 0 && path[0] != '/')\n        {\n            throw new ArgumentException($\"Route paths must start with `/`: {path}\", nameof(path));\n        }\n        foreach (var c in path)\n        {\n            if (!CharacterIsAcceptableForRoutePath(c))\n            {\n                throw new ArgumentException(\n                    $\"Route paths may contain only {AcceptableRoutePathCharsHumanDescription}: {path}\",\n                    nameof(path)\n                );\n            }\n        }\n    }\n\n    private static bool CharacterIsAcceptableForRoutePath(char c) =>\n        c is (>= 'a' and <= 'z') or (>= '0' and <= '9') or '-' or '_' or '~' or '/';\n}\n","sourceCodeStart":130,"sourceCodeEnd":165,"githubUrl":"https://github.com/clockworklabs/SpacetimeDB/blob/524b4487d949b61a07d4f39c862d1290259dfd20/crates/bindings-csharp/Runtime/Router.cs#L130-L165","documentation":"AssertValidPath requires every route path (including Nest prefixes) to be either empty or begin with '/'. A non-empty path whose first character is not '/' throws ArgumentException with the offending path embedded.","triggerScenarios":"Passing \"users\", \"api/users\", or a config-derived value that lost its leading slash to Get/Post/Put/Delete/Patch/Head/Options/Any/Nest/Merge.","commonSituations":"Route tables loaded from JSON/env config where the slash was trimmed; interpolating segment variables like $\"{base}/users\" with base = \"\" ; porting code from frameworks that accept slash-less paths.","solutions":["Add the leading slash: \"/users\" instead of \"users\"","Normalize config-driven paths through a helper that prefixes '/' when missing","Unit-test route construction at startup so bad config fails fast with a clear location"],"exampleFix":"// before\nvar router = Router.New().Get(config.UsersPath, listUsers); // UsersPath = \"users\"\n\n// after\nstatic string Route(string p) => p.Length > 0 && p[0] != '/' ? \"/\" + p : p;\nvar router = Router.New().Get(Route(config.UsersPath), listUsers);","handlingStrategy":"validation","validationCode":"static string NormalizeRoutePath(string p) =>\n    string.IsNullOrEmpty(p) ? p : (p[0] == '/' ? p : \"/\" + p);","typeGuard":"static bool HasLeadingSlash(string path) => path.Length == 0 || path[0] == '/';","tryCatchPattern":"try { router = router.Get(path, handler); }\ncatch (ArgumentException e) when (e.Message.Contains(\"must start with `/`\"))\n{ /* normalize the config-derived path and retry registration */ }","preventionTips":["Normalize every config/env-derived path through one helper before handing it to the Router","Assert path shape when loading route configuration"],"tags":["routing","path-validation","csharp"],"backgroundTag":"route-path-missing-slash","analyzedSha":"524b4487d949b61a07d4f39c862d1290259dfd20","analyzedAt":"2026-08-16T23:58:54.611Z","schemaVersion":2},"datasetVersion":"2026-08-17T04:17:16.089Z"}