reactiveui/refit · error · ArgumentException

URL {relativePathTemplate} has parameter {{{key}}}, but no m

Error message

URL {relativePathTemplate} has parameter {{{key}}}, but no method parameter matches

What it means

Thrown when a route template contains a {key} placeholder that no method parameter supplies. After locating a '{' and its matching '}', the builder extracts the key and throws an ArgumentException naming the unmatched placeholder and the template. It is a design-time contract violation surfaced at request build time.

Source

Thrown at src/Refit/GeneratedRequestRunner.cs:697

        if (allowUnmatchedParameter)
        {
            return path;
        }

        var i = path.IndexOf('{');
        if (i < 0)
        {
            return path;
        }

        var j = path.AsSpan(i).IndexOfAny('}', '/');
        if (j < 0 || path[j += i] != '}')
        {
            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>

View on GitHub (pinned to b455f65ecc)

Solutions

  1. Add a method parameter whose name matches the {key} in the route template exactly
  2. Fix the typo so the template placeholder and parameter name agree (C# identifiers are case-sensitive)
  3. Remove the unused {key} from the route template if it is no longer needed
  4. If unmatched placeholders are intentional, set allowUnmatchedParameter so the builder skips them instead of throwing

Example fix

// before
[Get("/items/{id}/children/{childId}")]
Task<IList<Child>> GetChildrenAsync(long id);
// childId has no parameter => throws

// after
[Get("/items/{id}/children/{childId}")]
Task<IList<Child>> GetChildrenAsync(long id, long childId);
Defensive patterns

Strategy: validation

Validate before calling

// Design-time: ensure every {key} in a route template has a matching parameter.
static IEnumerable<string> UnmatchedPlaceholders(string template, IEnumerable<string> paramNames)
{
    var nameSet = paramNames.ToHashSet();
    var matches = System.Text.RegularExpressions.Regex.Matches(template, @"\{(\w+)\}");
    foreach (System.Text.RegularExpressions.Match m in matches)
        if (!nameSet.Contains(m.Groups[1].Value))
            yield return m.Groups[1].Value;
}

Try / catch

try { await api.GetChildrenAsync(id, childId); }
catch (ArgumentException ex) when (ex.Message.Contains("but no method parameter matches"))
{
    // interface/template mismatch - fix the route or add the parameter
}

Prevention

When it happens

Trigger: An interface method declares a route like [Get("/items/{id}/sub/{subId}")] but only has an 'id' parameter (subId missing), or a placeholder name has a typo differing from the parameter name. Each template token must correspond to a parameter passed via the uriParams collection.

Common situations: Refactoring a route and forgetting to add/remove the matching parameter; copy-paste typos between the template placeholder and the parameter name; renaming a parameter without updating the template; relying on a parameter that was conditionally compiled out.

Related errors


AI-assisted analysis of reactiveui/refit@b455f65ecc (2026-08-13). Data as JSON: /api/errors/56f9f8ef8c773737. Report an issue: GitHub.