dotnet/wpf · error · XamlXmlWriterException
SR.ExpandPositionalParametersWithReadOnlyProperties
Error message
SR.ExpandPositionalParametersWithReadOnlyProperties
What it means
After matching a constructor parameter to a [ConstructorArgument] property, the writer checks that the property is writable; expansion works by inserting StartMember/EndMember assignment nodes, which requires a settable property. A read-only matched property triggers XamlXmlWriterException ExpandPositionalParametersWithReadOnlyProperties.
Solutions
- Add a setter (internal or private is not enough — make it settable) to the [ConstructorArgument] property.
- Remove [ConstructorArgument] from read-only properties and use a constructor overload the writer can expand.
- Re-expose the value via a settable backing property used only for XAML.
- Catch XamlXmlWriterException and write explicit member nodes with a different serialization strategy.
Example fix
// before
[ConstructorArgument("key")] public string Key { get; }
// after
[ConstructorArgument("key")] public string Key { get; set; } Defensive patterns
Strategy: type-guard
Validate before calling
foreach (var prop in caaProps) if (prop.IsReadOnly) throw new InvalidOperationException($"[ConstructorArgument] property {prop.Name} must be settable"); Type guard
bool IsSettableCaaProp(PropertyInfo p) => p.GetSetMethod(nonPublic: false) is not null && p.GetCustomAttribute<ConstructorArgumentAttribute>() is not null;
Try / catch
try { writer.WriteEndObject(); } catch (XamlXmlWriterException ex) when (ex.Message.Contains("ReadOnly")) { /* serialize with explicit members instead */ } Prevention
- Give all [ConstructorArgument] properties public setters.
- Do not mark ConstructorArgument properties as get-only in immutable designs.
- Round-trip test markup extensions in CI.
When it happens
Trigger: Expanding positional parameters where a matched [ConstructorArgument] property has IsReadOnly == true (get-only property, indexer, or read-only collection property).
Common situations: Immutable-style markup extensions exposing get-only properties with [ConstructorArgument], porting types that changed from settable to read-only properties, source-generated properties without setters.
Understand the failure class
Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.
Related errors
- SR.ConstructorNotFoundForGivenPositionalParameters
- SR.ExpandPositionalParametersWithoutUnderlyingType…
- SR.MustNotCallSetter
- SR.MustNotCallSetter
- XamlXmlWriterException(SR.ExpandPositionalParametersinTypeWi…
AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14).
Data as JSON: /api/errors/745273afc6cda22a.
Report an issue: GitHub.
Appendix: source
Thrown at src/Microsoft.DotNet.Wpf/src/System.Xaml/System/Xaml/XamlXmlWriter.cs:1951
if ((potentialProperty.Type.UnderlyingType == paraminfo.ParameterType) &&
(XamlObjectReader.GetConstructorArgument(potentialProperty) == paraminfo.Name))
{
matchingProperty = potentialProperty;
break;
}
}
if (matchingProperty is null)
{
throw new XamlXmlWriterException(SR.ConstructorNotFoundForGivenPositionalParameters);
}
XamlMember member = objectXamlType.GetMember(matchingProperty.Name);
Debug.Assert(member is not null);
if (member.IsReadOnly)
{
throw new XamlXmlWriterException(SR.ExpandPositionalParametersWithReadOnlyProperties);
}
writer.ppStateInfo.NodesList[i].Insert(0, new XamlNode(XamlNodeType.StartMember, member));
writer.ppStateInfo.NodesList[i].Add(new XamlNode(XamlNodeType.EndMember));
}
}
private ParameterInfo[] GetParametersInfo(XamlType objectXamlType, int numOfParameters)
{
IList<XamlType> paramXamlTypes = objectXamlType.GetPositionalParameters(numOfParameters);
if (paramXamlTypes is null)
{
throw new XamlXmlWriterException(SR.ConstructorNotFoundForGivenPositionalParameters);
}
Type[] paramClrTypes = new Type[numOfParameters];
View on GitHub (pinned to 81131a70a4)