{"record":{"id":"09c1d4e29f1258cc","repo":"clockworklabs/SpacetimeDB","slug":"route-paths-must-start-with-path","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/6dee26c6efc2856793e12b148a59742964f5d783/crates/bindings-csharp/Runtime/Router.cs#L130-L165","documentation":"AssertValidPath runs on every route registration (Get/Post/.../Any/Nest) and requires the path to be null-checked and, when non-empty, to begin with '/'. A path missing the leading slash — e.g. \"users\" instead of \"/users\" — is rejected immediately with this ArgumentException (param name 'path'). The empty string \"\" is the one allowed slash-less value.","triggerScenarios":"router.Get(\"users\", h), router.Nest(\"v1\", sub), or building paths with string concatenation that drops the leading '/'; passing a path variable configured without the initial slash.","commonSituations":"Porting routes from frameworks that accept slash-less paths (Express/Koa style); assembling paths from config or constants where the '/' got trimmed; typos in route tables.","solutions":["Prefix the path with '/': \"/users\"","If paths come from configuration, normalize them at load time: path.StartsWith('/') ? path : \"/\" + path","Keep route constants in one place and lint them for the leading slash"],"exampleFix":"// before\nrouter.Get(\"users\", listUsers); // throws: Route paths must start with `/`\n\n// after\nrouter.Get(\"/users\", listUsers);","handlingStrategy":"validation","validationCode":"// Normalize before registering:\nstatic string NormalizeRoutePath(string p) =>\n    string.IsNullOrEmpty(p) ? \"/\" : (p.StartsWith('/') ? p : \"/\" + p);","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Keep all route strings as constants starting with '/'","Normalize externally sourced paths (config/DB) once at load time","Write a unit test that asserts every registered path matches ^/"],"tags":["csharp","router","http","path-validation"],"backgroundTag":"invalid-route-path","analyzedSha":"6dee26c6efc2856793e12b148a59742964f5d783","analyzedAt":"2026-08-20T06:08:37.179Z","contentChangedAt":"2026-08-20T06:08:37.179Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}