reactiveui/refit · error · ArgumentException
The [Url] parameter value "{value}" must be an absolute URI
Error message
The [Url] parameter value "{value}" must be an absolute URI (for example "https://host/path"). What it means
RequireAbsoluteUrl rejects a [Url] parameter whose value is not an absolute URI. The method accepts a string or Uri, takes the original string form, and uses Uri.TryCreate with UriKind.Absolute; any null, empty, relative, or malformed value yields an ArgumentException pointing at the offending value in the message.
Source
Thrown at src/Refit/GeneratedRequestRunner.cs:81
var basePath = client.BaseAddress?.AbsolutePath
?? throw new InvalidOperationException("BaseAddress must be set on the HttpClient instance");
basePath = basePath == "/" ? string.Empty : basePath.TrimEnd('/');
var absolute = new Uri(QueryUriFormatBase, basePath + relativePath);
return new(absolute.GetComponents(UriComponents.PathAndQuery, queryUriFormat), UriKind.Relative);
}
/// <summary>Validates that a <c>[Url]</c> parameter value is an absolute URI, returning its string form as the
/// base for a full-URL request that bypasses the client's base address. A <see cref="string"/> value is used as
/// written; a <see cref="Uri"/> value contributes its <see cref="Uri.OriginalString"/>.</summary>
/// <param name="url">The <c>[Url]</c> parameter value: a <see cref="string"/> or a <see cref="Uri"/>.</param>
/// <returns>The absolute URI's string form.</returns>
/// <exception cref="ArgumentException"><paramref name="url"/> is <see langword="null"/>, empty, or not an absolute URI.</exception>
public static string RequireAbsoluteUrl(object? url)
{
var text = url is Uri uri ? uri.OriginalString : url as string;
return Uri.TryCreate(text, UriKind.Absolute, out _)
? text!
: throw new ArgumentException(FormatAbsoluteUrlError(url), nameof(url));
}
/// <summary>Builds the request path for a generated request from a template.</summary>
/// <param name="relativePathTemplate">The method's relative path, including any leading slash and query string.</param>
/// <param name="allowUnmatchedParameter">Whether to allow unmatched URL parameters.</param>
/// <param name="uriParams">The replacement uri parameters, ordered by template position.</param>
/// <returns>A path with all the placeholder parameters in the path template replaced.</returns>
/// <exception cref="ArgumentException">
/// A URI template parameter is not available in the provided parameter span and unmatched URL parameters aren't allowed.
/// </exception>
/// <remarks>Generated call sites pass the replacements as a collection expression. On C# 12 and a runtime with inline
/// array support (net8.0+) that materializes on the stack, so any number of path parameters is expanded without a heap
/// allocation; older consumers pass a small array via the same signature.</remarks>
public static string BuildRequestPath(
string relativePathTemplate,
bool allowUnmatchedParameter,
ReadOnlySpan<((int StartIdx, int EndIdx) Range, string? Value)> uriParams)
{View on GitHub (pinned to b455f65ecc)
Solutions
- Pass a fully-qualified URL string such as "https://host/api/resource" to the [Url] parameter
- If passing a Uri, construct it with UriKind.Absolute (e.g. new Uri("https://host/path", UriKind.Absolute))
- Validate or default the URL at the call site before invoking the method
- If you meant a relative path under the base address, remove [Url] from the parameter and use the normal route template instead
Example fix
// before
Task<Thing> GetAsync([Url] string url);
await api.GetAsync("/things/42"); // relative => throws
// after
await api.GetAsync("https://api.example.com/things/42"); Defensive patterns
Strategy: validation
Validate before calling
static string EnsureAbsoluteUrl(string url) =>
Uri.TryCreate(url, UriKind.Absolute, out _)
? url
: throw new ArgumentException($"Expected an absolute URL, got: {url}", nameof(url));
await api.GetAsync(EnsureAbsoluteUrl(candidate)); Type guard
static bool IsAbsoluteUrl(string? url) =>
!string.IsNullOrWhiteSpace(url) && Uri.TryCreate(url, UriKind.Absolute, out _); Try / catch
try { await api.GetAsync(url); }
catch (ArgumentException ex) when (ex.Message.Contains("must be an absolute URI"))
{
// log the bad URL and prompt the user / fall back to a configured host
} Prevention
- Validate URLs at the boundary before passing them to [Url] parameters
- Prefer constructing Uri with UriKind.Absolute to fail early at the source
- Keep a helper that normalizes incoming strings to absolute URIs
- Add unit tests covering null, empty, relative, and scheme-less inputs
When it happens
Trigger: An interface method has a parameter marked [Url] and the caller passes a relative path (e.g. "/foo"), a scheme-less string, a null, or a Uri created with UriKind.Relative. Used to bypass the client base address, the value must carry its own scheme and host.
Common situations: Passing a path fragment where a full URL is expected; reading a URL from config that came back null/empty; supplying a Uri built from a relative string; dynamically building the URL and accidentally stripping the scheme.
Related errors
- URL path {relativePath} must not contain CR or LF characters
- URL {relativePathTemplate} has parameter {{{key}}}, but no m
- URL path {relativePath} must start with '/' and be of the fo
- `hostUrl` must not be null or whitespace.
- Content must be an 'application/problem+json' compliant json
AI-assisted analysis of reactiveui/refit@b455f65ecc (2026-08-13).
Data as JSON: /api/errors/705915471ff975ba.
Report an issue: GitHub.