dotnet/aspnetcore · error · InvalidOperationException

The type ' ' declares more than one parameter matching the…

Error message

The type '{targetType.FullName}' declares more than one parameter matching the name '{propertyName.ToLowerInvariant()}'. Parameter names are case-insensitive and must be unique.

What it means

WritersForType builds its parameter-name cache case-insensitively (StringComparer.OrdinalIgnoreCase). When two properties both resolve to the same parameter name (e.g., 'Count' and 'count'), the second registration collides and throws. Blazor parameter names are case-insensitive on the consumer side, so duplicate names differing only by case are ambiguous and rejected at cache-construction time.

Solutions

  1. Rename one of the colliding parameters so the names are unique case-insensitively.
  2. If the collision comes from inheritance, remove the duplicate in the derived type or rename the base.
  3. Establish a casing convention (PascalCase for parameters) across the component hierarchy.

Example fix

// before
[Parameter] public string? Title { get; set; }
[Parameter] public string? title { get; set; } // throws

// after
[Parameter] public string? Title { get; set; }
[Parameter] public string? Subtitle { get; set; }
Defensive patterns

Strategy: validation

Validate before calling

// Detect case-insensitive parameter name collisions across the type hierarchy.
var seen = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
foreach (var p in typeof(MyComponent).GetProperties(
    BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance))
{
    bool isParam = p.GetCustomAttribute<ParameterAttribute>() != null
        || p.GetCustomAttributes().OfType<CascadingParameterAttributeBase>().Any();
    if (!isParam) continue;
    if (!seen.Add(p.Name))
        throw new InvalidOperationException($"Duplicate parameter name '{p.Name}' (case-insensitive).");
}

Prevention

When it happens

Trigger: Declaring two [Parameter] (or [CascadingParameter]) properties on the same component whose names differ only by case, e.g., 'Title' and 'title'. The collision is detected when _underlyingWriters already contains the lower-cased key. Inheritance can also cause it if base and derived declare same-named parameters.

Common situations: Refactoring that introduces a similarly-named parameter. Inherited components overriding or shadowing a base parameter with a differently-cased duplicate. Copy-paste errors. Casing inconsistencies between C# property name and a Razor attribute.

Related errors


AI-assisted analysis of dotnet/aspnetcore@3600ca084e (2026-08-11). Data as JSON: /api/errors/dae09a1338998cbc. Report an issue: GitHub.

Appendix: source

Thrown at src/Components/Components/src/Reflection/ComponentProperties.cs:333

                    continue;
                }

                var propertyName = propertyInfo.Name;
                if (parameterAttribute != null && (propertyInfo.SetMethod == null || !propertyInfo.SetMethod.IsPublic))
                {
                    throw new InvalidOperationException(
                        $"The type '{targetType.FullName}' declares a parameter matching the name '{propertyName}' that is not public. Parameters must be public.");
                }

                var propertySetter = new PropertySetter(targetType, propertyInfo)
                {
                    AcceptsDirectParameters = acceptsDirectParameters,
                    AcceptsCascadingParameters = acceptsCascadingParameters,
                };

                if (_underlyingWriters.ContainsKey(propertyName))
                {
                    throw new InvalidOperationException(
                        $"The type '{targetType.FullName}' declares more than one parameter matching the " +
                        $"name '{propertyName.ToLowerInvariant()}'. Parameter names are case-insensitive and must be unique.");
                }

                _underlyingWriters.Add(propertyName, propertySetter);

                if (parameterAttribute != null && parameterAttribute.CaptureUnmatchedValues)
                {
                    // This is an "Extra" parameter.
                    //
                    // There should only be one of these.
                    if (CaptureUnmatchedValuesWriter != null)
                    {
                        ThrowForMultipleCaptureUnmatchedValuesParameters(targetType);
                    }

                    // It must be able to hold a Dictionary<string, object> since that's what we create.
                    if (!propertyInfo.PropertyType.IsAssignableFrom(typeof(Dictionary<string, object>)))

View on GitHub (pinned to 3600ca084e)