{"record":{"id":"14950dd76da8d7a4","repo":"reactiveui/refit","slug":"url-path-relativepath-must-start-with-and-be-14950d","errorCode":null,"errorMessage":"URL path {relativePath} must start with '/' and be of the form '/foo/bar/baz'","messagePattern":"URL path (.+?) must start with '/' and be of the form '/foo/bar/baz'","errorType":"validation","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"src/Refit/GeneratedRequestRunner.cs","lineNumber":711,"sourceCode":"            return path;\n        }\n\n        var key = path[(i + 1)..j];\n        throw new ArgumentException(\n            $\"URL {relativePathTemplate} has parameter {{{key}}}, but no method parameter matches\");\n    }\n\n    /// <summary>Rejects a no-leading-slash path under legacy resolution, matching the reflection request builder.</summary>\n    /// <param name=\"relativePath\">The resolved relative request path.</param>\n    /// <exception cref=\"ArgumentException\">The path is non-empty and does not start with '/'.</exception>\n    internal static void RequireLeadingSlashUnderLegacy(string relativePath)\n    {\n        if (relativePath.Length == 0 || relativePath[0] == '/')\n        {\n            return;\n        }\n\n        throw new ArgumentException(\n            $\"URL path {relativePath} must start with '/' and be of the form '/foo/bar/baz'\");\n    }\n\n    /// <summary>Builds the message describing an invalid <c>[Url]</c> parameter value.</summary>\n    /// <param name=\"value\">The rejected value.</param>\n    /// <returns>The exception message.</returns>\n    internal static string FormatAbsoluteUrlError(object? value) =>\n        $\"The [Url] parameter value \\\"{value}\\\" must be an absolute URI (for example \\\"https://host/path\\\").\";\n\n    /// <summary>Adds one pre-boxed configured request property or option value.</summary>\n    /// <param name=\"request\">The request to modify.</param>\n    /// <param name=\"key\">The property key.</param>\n    /// <param name=\"value\">The pre-boxed property value.</param>\n#if NET6_0_OR_GREATER\n    internal static void AddBoxedRequestProperty(HttpRequestMessage request, string key, object value) => request.Options.Set(new(key), value);\n#else\n    internal static void AddBoxedRequestProperty(HttpRequestMessage request, string key, object value) => request.Properties[key] = value;\n#endif","sourceCodeStart":693,"sourceCodeEnd":729,"githubUrl":"https://github.com/reactiveui/refit/blob/b455f65ecc4c97d092317e349cb775f9cfc6bcdf/src/Refit/GeneratedRequestRunner.cs#L693-L729","documentation":"RequireLeadingSlashUnderLegacy rejects a non-empty relative path that does not start with '/', mirroring the legacy reflection request builder's behavior. Under legacy resolution a leading slash is required so the base path concatenation yields a well-formed absolute path; otherwise an ArgumentException is thrown.","triggerScenarios":"Under UrlResolutionMode.Legacy, a route template or computed relative path that is non-empty but lacks a leading '/', e.g. [Get(\"things/42\")] instead of [Get(\"/things/42\")], or a [Url]/path substitution that produces a bare segment.","commonSituations":"Copying a route from a framework that omits leading slashes; building a path dynamically and forgetting the '/'; switching resolution mode to legacy on an interface whose templates were authored for Rfc3986 (which is lenient).","solutions":["Add a leading '/' to every non-empty route template: [Get(\"/things/42\")]","If building the path in code, prefix it with '/' before it reaches the builder","Switch to UrlResolutionMode.Rfc3986 if the slash-less convention must be kept (it emits the path verbatim)","Audit all interface route templates after changing the resolution mode to legacy"],"exampleFix":"// before\n[Get(\"things/{id}\")]\nTask<Thing> GetAsync(long id); // legacy => throws, no leading slash\n\n// after\n[Get(\"/things/{id}\")]\nTask<Thing> GetAsync(long id);","handlingStrategy":"validation","validationCode":"// Ensure every non-empty route template starts with '/' under legacy resolution.\nstatic string EnsureLeadingSlash(string route) =>\n    string.IsNullOrEmpty(route) || route[0] == '/' ? route : \"/\" + route;","typeGuard":"static bool HasLeadingSlash(string route) =>\n    route.Length == 0 || route[0] == '/';","tryCatchPattern":"try { await api.GetAsync(); }\ncatch (ArgumentException ex) when (ex.Message.Contains(\"must start with '/'\"))\n{\n    // fix the route template to begin with '/' or switch to Rfc3986 resolution\n}","preventionTips":["Standardize all route templates to begin with '/'","Add a lint test that asserts every [Get]/[Post]/etc. template starts with '/' when using legacy mode","Keep resolution mode consistent across the app to avoid mixed conventions","When switching to legacy resolution, audit all templates immediately"],"tags":["routing","url-resolution","validation","argument","template"],"backgroundTag":null,"analyzedSha":"b455f65ecc4c97d092317e349cb775f9cfc6bcdf","analyzedAt":"2026-08-13T21:20:57.878Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}