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
Under the RefitLegacy URL resolution mode, any non-empty relative path on an HTTP attribute must begin with '/'. This guard enforces the legacy '/foo/bar' convention and also rejects CR/LF characters to prevent header/URL injection. Modern (non-legacy) mode is lenient about the leading slash.
Source
Thrown at src/Refit.Reflection/RestMethodInfoInternal.cs:320
internal static PropertyInfo[] GetParameterProperties(ParameterInfo parameter) =>
ReflectionPropertyHelpers.GetReadablePublicInstanceProperties(parameter.ParameterType);
/// <summary>Verifies that the relative URL path is well formed and free of injection characters.</summary>
/// <param name="relativePath">The relative URL path to validate.</param>
/// <param name="urlResolution">The URL resolution mode; the leading-slash requirement is relaxed under <see cref="UrlResolutionMode.Rfc3986"/>.</param>
/// <exception cref="ArgumentException"><paramref name="relativePath"/> contains a CR or LF character, or it does not
/// start with '/' under <see cref="UrlResolutionMode.RefitLegacy"/>.</exception>
internal static void VerifyUrlPathIsSane(string relativePath, UrlResolutionMode urlResolution)
{
if (string.IsNullOrEmpty(relativePath))
{
return;
}
if (urlResolution == UrlResolutionMode.RefitLegacy
&& !StringHelpers.StartsWith(relativePath, '/'))
{
throw new ArgumentException(
$"URL path {relativePath} must start with '/' and be of the form '/foo/bar/baz'");
}
// CRLF injection protection
if (!StringHelpers.ContainsCrOrLf(relativePath))
{
return;
}
throw new ArgumentException(
$"URL path {relativePath} must not contain CR or LF characters");
}
/// <summary>Adds headers from a <see cref="HeadersAttribute"/> into the accumulated map.</summary>
/// <param name="headersAttribute">The header attribute to process.</param>
/// <param name="ret">The accumulated map, created as needed.</param>
internal static void AddHeaders(HeadersAttribute headersAttribute, ref Dictionary<string, string?>? ret)
{View on GitHub (pinned to b455f65ecc)
Solutions
- Prefix every relative path with '/', e.g. [Get("/users/{id}")].
- If you rely on paths without a leading slash, switch UrlResolutionMode to the non-legacy mode in RefitSettings.
- Ensure no CR/LF characters are interpolated into path templates (sanitize any data used in {path} parameters).
Example fix
// before
[Get("users/{id}")] Task<User> GetAsync(string id); // RefitLegacy -> throws
// after
[Get("/users/{id}")] Task<User> GetAsync(string id); Defensive patterns
Strategy: validation
Validate before calling
static void AssertPathStartsWithSlash(string path, UrlResolutionMode mode) {
if (mode == UrlResolutionMode.RefitLegacy && !string.IsNullOrEmpty(path) && !path.StartsWith("/"))
throw new InvalidOperationException($"Path '{path}' must start with '/' in RefitLegacy mode.");
if (path.IndexOfAny(new[] { '\r', '\n' }) >= 0)
throw new InvalidOperationException("Path must not contain CR/LF.");
} Prevention
- Prefix relative paths with '/' in all [Http*] attributes.
- Switch to non-legacy UrlResolutionMode only intentionally and document why.
- Sanitize any data interpolated into {path} parameters to strip CR/LF.
When it happens
Trigger: A [Get("users/{id}")] style attribute (no leading slash) is used while RefitSettings.UrlResolution is set to UrlResolutionMode.RefitLegacy; or a path contains a CR/LF character in any mode.
Common situations: Upgrading from old Refit where paths without '/' were silently accepted; switching UrlResolutionMode; templated path that accidentally includes a newline (injection or bad data).
Related errors
- A [Url] method must not also declare a path template; [Url]
- Sequence contains more than one matching element
- Sequence contains no matching element
- targetInterface must be an Interface
- URL {relativePath} has parameter {rawName}, but no method pa
AI-assisted analysis of reactiveui/refit@b455f65ecc (2026-08-13).
Data as JSON: /api/errors/f87f2dfe366872bc.
Report an issue: GitHub.