dotnet/aspnetcore · error · InvalidOperationException
The property ' ' on component type ' ' cannot be used with…
Error message
The property '{propertyInfo.Name}' on component type '{targetType.FullName}' cannot be used with 'ParameterAttribute.CaptureUnmatchedValues' because it has the wrong type. The property must be assignable from 'Dictionary<string, object>'. What it means
ThrowForInvalidCaptureUnmatchedValuesParameterType validates that a property annotated with [Parameter(CaptureUnmatchedValues = true)] is assignable from Dictionary<string, object>. If the property's type is, say, List<string>, object[], or a custom dictionary without the right key/value types, the framework cannot splat arbitrary unmatched attributes into it and throws at cache-construction time.
Solutions
- Change the property type to Dictionary<string, object> (the only supported sink type).
- If you need typed access, keep the Dictionary<string, object> sink and project its entries into typed fields in OnParametersSet.
- Do not use CaptureUnmatchedValues if you cannot accept the required dictionary type.
Example fix
// before
[Parameter(CaptureUnmatchedValues = true)]
public Dictionary<string, string>? Attributes { get; set; } // throws
// after
[Parameter(CaptureUnmatchedValues = true)]
public Dictionary<string, object>? Attributes { get; set; } Defensive patterns
Strategy: type-guard
Type guard
static bool IsValidCaptureSinkType(PropertyInfo p)
{
var t = p.PropertyType;
return typeof(Dictionary<string, object>).IsAssignableFrom(t);
}
var sink = typeof(MyComponent).GetProperties()
.First(p => p.GetCustomAttribute<ParameterAttribute>()?.CaptureUnmatchedValues == true);
Assert.True(IsValidCaptureSinkType(sink)); Prevention
- Use Dictionary<string, object> as the capture-sink type.
- Add a unit test verifying the sink type is assignable from Dictionary<string, object>.
- Project typed values from the dictionary in OnParametersSet rather than changing the sink type.
When it happens
Trigger: Declaring [Parameter(CaptureUnmatchedValues = true)] on a property whose type is not assignable from Dictionary<string, object> (e.g., IDictionary<string, string>, Dictionary<string, string>, List<KeyValuePair<string,object>>, object, dynamic). The check happens when the component type's writers cache is built.
Common situations: Wanting strongly-typed attribute bags and using Dictionary<string, string> instead of Dictionary<string, object>. Copying a pattern from a non-Blazor framework that used different collection types. Misunderstanding the required signature of the capture sink.
Related errors
- Multiple properties were found on component type
- Object of type ' ' does not have a property matching the…
- Object of type ' ' has a property matching the name ' '…
- The property ' ' on component type ' ' cannot be set…
- The type ' ' declares a parameter matching the name ' '…
AI-assisted analysis of dotnet/aspnetcore@3600ca084e (2026-08-11).
Data as JSON: /api/errors/b11e2b5f72e939e7.
Report an issue: GitHub.
Appendix: source
Thrown at src/Components/Components/src/Reflection/ComponentProperties.cs:270
if (property.GetCustomAttribute<ParameterAttribute>()?.CaptureUnmatchedValues == true)
{
propertyNames.Add(property.Name);
}
}
propertyNames.Sort(StringComparer.Ordinal);
throw new InvalidOperationException(
$"Multiple properties were found on component type '{targetType.FullName}' with " +
$"'{nameof(ParameterAttribute)}.{nameof(ParameterAttribute.CaptureUnmatchedValues)}'. Only a single property " +
$"per type can use '{nameof(ParameterAttribute)}.{nameof(ParameterAttribute.CaptureUnmatchedValues)}'. Properties:" + Environment.NewLine +
string.Join(Environment.NewLine, propertyNames));
}
[DoesNotReturn]
private static void ThrowForInvalidCaptureUnmatchedValuesParameterType(Type targetType, PropertyInfo propertyInfo)
{
throw new InvalidOperationException(
$"The property '{propertyInfo.Name}' on component type '{targetType.FullName}' cannot be used " +
$"with '{nameof(ParameterAttribute)}.{nameof(ParameterAttribute.CaptureUnmatchedValues)}' because it has the wrong type. " +
$"The property must be assignable from 'Dictionary<string, object>'.");
}
private sealed class WritersForType
{
private const int MaxCachedWriterLookups = 100;
private readonly Dictionary<string, PropertySetter> _underlyingWriters;
private readonly ConcurrentDictionary<string, PropertySetter?> _referenceEqualityWritersCache;
public WritersForType([DynamicallyAccessedMembers(Component)] Type targetType)
{
_underlyingWriters = new Dictionary<string, PropertySetter>(StringComparer.OrdinalIgnoreCase);
_referenceEqualityWritersCache = new ConcurrentDictionary<string, PropertySetter?>(ReferenceEqualityComparer.Instance);
foreach (var propertyInfo in GetCandidateBindableProperties(targetType))
{View on GitHub (pinned to 3600ca084e)