reactiveui/refit · error · ArgumentException

Parameter {owner.Name} matches both a parameter and nested p

Error message

Parameter {owner.Name} matches both a parameter and nested parameter on a parameter object

What it means

The same parameter index is already present in the parameter map as a direct (non-object-property) binding, and the code is now trying to add an object/nested-property binding for it. Refit forbids a parameter being both a direct route binding and a nested object-property source simultaneously, because the two bindings would conflict.

Source

Thrown at src/Refit.Reflection/RestMethodInfoInternal.ParameterBinding.cs:249

    /// <exception cref="ArgumentException"><paramref name="owner"/> is already bound as a route parameter in its own
    /// right, so it cannot also supply a nested property.</exception>
    internal static void AddObjectPropertyParameter(
        ParameterInfo[] parameterInfo,
        Dictionary<int, RestMethodParameterInfo> ret,
        List<ParameterFragment> fragmentList,
        string name,
        ParameterInfo owner,
        IReadOnlyList<PropertyInfo> propertyChain,
        bool isOptional)
    {
        var parameterIndex = Array.IndexOf(parameterInfo, owner);

        // If we already have this parameter, add an additional ParameterProperty.
        if (ret.TryGetValue(parameterIndex, out var value2))
        {
            if (!value2.IsObjectPropertyParameter)
            {
                throw new ArgumentException(
                    $"Parameter {owner.Name} matches both a parameter and nested parameter on a parameter object");
            }

            value2.ParameterProperties.Add(new(name, propertyChain));
            fragmentList.Add(
                ParameterFragment.DynamicObject(parameterIndex, value2.ParameterProperties.Count - 1, isOptional));
            return;
        }

        var restMethodParameterInfo = new RestMethodParameterInfo(true, owner);
        restMethodParameterInfo.ParameterProperties.Add(new(name, propertyChain));

        var idx = Array.IndexOf(parameterInfo, restMethodParameterInfo.ParameterInfo);
        fragmentList.Add(ParameterFragment.DynamicObject(idx, 0, isOptional));
#if NET6_0_OR_GREATER
        _ = ret.TryAdd(idx, restMethodParameterInfo);
#else
        if (ret.ContainsKey(idx))

View on GitHub (pinned to b455f65ecc)

Solutions

  1. Avoid binding the same parameter both directly and via nested properties; split into distinct parameters.
  2. Use [AliasAs] or separate DTOs so each placeholder has a single, unambiguous source.
  3. Review the parameter object's properties and remove the overlapping direct binding.

Example fix

// before
[Get("/{obj}/{obj.Name}")] Task GetAsync(MyObj obj); // obj bound twice

// after
[Get("/{id}/{name}")] Task GetAsync(string id, string name);
Defensive patterns

Strategy: validation

Validate before calling

// Avoid binding the same parameter both directly and via nested property chains.
// Ensure each placeholder resolves to exactly one source (param or property).

Prevention

When it happens

Trigger: A method parameter is bound directly to a route placeholder AND the same parameter object is also referenced through a nested property chain for another placeholder, producing a double registration on the same index.

Common situations: A parameter object used both as a whole for {param} and decomposed into {param.Prop}; overlapping [AliasAs]/property bindings on a shared object; complex DTO bound multiple ways.

Related errors


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