{"record":{"id":"75167f17ead91651","repo":"clockworklabs/SpacetimeDB","slug":"route-paths-may-contain-only-acceptableroutepathc","errorCode":null,"errorMessage":"Route paths may contain only {AcceptableRoutePathCharsHumanDescription}: {path}","messagePattern":"Route paths may contain only (.+?): (.+?)","errorType":"exception","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"crates/bindings-csharp/Runtime/Router.cs","lineNumber":154,"sourceCode":"        }\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":136,"sourceCodeEnd":165,"githubUrl":"https://github.com/clockworklabs/SpacetimeDB/blob/6dee26c6efc2856793e12b148a59742964f5d783/crates/bindings-csharp/Runtime/Router.cs#L136-L165","documentation":"The second rule enforced by AssertValidPath: every character of the path must satisfy CharacterIsAcceptableForRoutePath — ASCII lowercase a-z, digits 0-9, and the punctuation '-', '_', '~', plus '/' as separator. Anything else — uppercase letters, dots, colons, braces, spaces, non-ASCII — throws this ArgumentException. Notably the SpacetimeDB router has NO parameter segments, so '/users/{id}' is rejected twice over (uppercase would be fine only in lowercase; '{', '}' are never allowed).","triggerScenarios":"router.Get(\"/Users\", h) (uppercase U); router.Get(\"/api/v1.0/status\", h) (dot); router.Get(\"/users/{id}\", h) (braces — path params are unsupported); any path containing ':' or non-ASCII characters.","commonSituations":"Porting ASP.NET/Express routes with {param} or :param syntax; casing conventions like PascalCase API paths; version suffixes like 'v1.0'; expecting wildcard segments that this router does not support.","solutions":["Lowercase the whole path and strip unsupported characters: '/users/all'","Replace version dots: '/api/v1-0' or '/api/v1_0'","Drop path-parameter syntax — register one concrete route per key value or restructure to use query/header data inside the handler"],"exampleFix":"// before - uppercase, dot and braces are all rejected\nrouter.Get(\"/Api/V1.0/users/{id}\", h);\n\n// after - lowercase letters, digits and -_~/ only\nrouter.Get(\"/api/v1-0/users\", h);","handlingStrategy":"validation","validationCode":"// Allowed: ASCII lowercase, digits, '-', '_', '~', '/'\nstatic bool IsValidRoutePath(string p) =>\n    p.Length == 0 || (p[0] == '/' && p.All(c => c is (>= 'a' and <= 'z') or (>= '0' and <= '9') or '-' or '_' or '~' or '/'));","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Lowercase route paths; encode versions with '-' or '_' instead of '.'","Remember this router is static-only: no {param}/:param segments — put variable data in headers/body","Unit-test your route table against the same character rule the router enforces"],"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"}