reactiveui/refit · error · ArgumentException
URL path {relativePath} must start with '/' and be of the fo
Error message
URL path {relativePath} must start with '/' and be of the form '/foo/bar/baz' What it means
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.
Source
Thrown at src/Refit/GeneratedRequestRunner.cs:711
return path;
}
var key = path[(i + 1)..j];
throw new ArgumentException(
$"URL {relativePathTemplate} has parameter {{{key}}}, but no method parameter matches");
}
/// <summary>Rejects a no-leading-slash path under legacy resolution, matching the reflection request builder.</summary>
/// <param name="relativePath">The resolved relative request path.</param>
/// <exception cref="ArgumentException">The path is non-empty and does not start with '/'.</exception>
internal static void RequireLeadingSlashUnderLegacy(string relativePath)
{
if (relativePath.Length == 0 || relativePath[0] == '/')
{
return;
}
throw new ArgumentException(
$"URL path {relativePath} must start with '/' and be of the form '/foo/bar/baz'");
}
/// <summary>Builds the message describing an invalid <c>[Url]</c> parameter value.</summary>
/// <param name="value">The rejected value.</param>
/// <returns>The exception message.</returns>
internal static string FormatAbsoluteUrlError(object? value) =>
$"The [Url] parameter value \"{value}\" must be an absolute URI (for example \"https://host/path\").";
/// <summary>Adds one pre-boxed configured request property or option value.</summary>
/// <param name="request">The request to modify.</param>
/// <param name="key">The property key.</param>
/// <param name="value">The pre-boxed property value.</param>
#if NET6_0_OR_GREATER
internal static void AddBoxedRequestProperty(HttpRequestMessage request, string key, object value) => request.Options.Set(new(key), value);
#else
internal static void AddBoxedRequestProperty(HttpRequestMessage request, string key, object value) => request.Properties[key] = value;
#endifView on GitHub (pinned to b455f65ecc)
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
Example fix
// before
[Get("things/{id}")]
Task<Thing> GetAsync(long id); // legacy => throws, no leading slash
// after
[Get("/things/{id}")]
Task<Thing> GetAsync(long id); Defensive patterns
Strategy: validation
Validate before calling
// Ensure every non-empty route template starts with '/' under legacy resolution.
static string EnsureLeadingSlash(string route) =>
string.IsNullOrEmpty(route) || route[0] == '/' ? route : "/" + route; Type guard
static bool HasLeadingSlash(string route) =>
route.Length == 0 || route[0] == '/'; Try / catch
try { await api.GetAsync(); }
catch (ArgumentException ex) when (ex.Message.Contains("must start with '/'"))
{
// fix the route template to begin with '/' or switch to Rfc3986 resolution
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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).
Related errors
- URL {relativePathTemplate} has parameter {{{key}}}, but no m
- The [Url] parameter value "{value}" must be an absolute URI
- Content must be an 'application/problem+json' compliant json
- URL {relativePath} has parameter {rawName}, but no method pa
- Parameter {owner.Name} matches both a parameter and nested p
AI-assisted analysis of reactiveui/refit@b455f65ecc (2026-08-13).
Data as JSON: /api/errors/14950dd76da8d7a4.
Report an issue: GitHub.