dotnet/wpf · error · ArgumentException

SR.Format(SR.MustBeOfType, "value", "SystemResourceKey or…

Error message

SR.Format(SR.MustBeOfType, "value", "SystemResourceKey or SystemThemeKey")

What it means

SystemKeyConverter.ConvertTo only accepts SystemResourceKey or SystemThemeKey as the value being converted; any other object type makes it throw ArgumentException. The converter exists so WPF system resource keys (e.g. SystemParameters.CaptionHeightKey) can round-trip to a StaticExtension markup string for XAML serialization. Passing an unconvertible value is a programming error, so the exception names the two accepted types.

Solutions

  1. Check the value's type before calling ConvertTo and only pass SystemResourceKey or SystemThemeKey instances.
  2. If converting other key kinds, dispatch to the correct converter (e.g. the TypeConverter for that key's type) instead of SystemKeyConverter.
  3. Wrap the ConvertTo call in try/catch(ArgumentException) when the input is untrusted and skip/convert via ToString() instead.

Example fix

// before
string s = (string)converter.ConvertTo(null, CultureInfo.InvariantCulture, value, typeof(MarkupExtension));
// after
if (value is SystemResourceKey || value is SystemThemeKey)
{
    string s = (string)converter.ConvertTo(null, CultureInfo.InvariantCulture, value, typeof(MarkupExtension));
}
else
{
    string s = value?.ToString() ?? string.Empty; // or skip non-system keys
}
Defensive patterns

Strategy: type-guard

Validate before calling

if (value is SystemResourceKey || value is SystemThemeKey)
{
    var ext = (MarkupExtension)converter.ConvertTo(null, CultureInfo.InvariantCulture, value, typeof(MarkupExtension));
}
else
{
    throw new ArgumentException($"Cannot convert {value?.GetType().Name}; expected SystemResourceKey or SystemThemeKey");
}

Type guard

bool IsSystemKey(object value) => value is SystemResourceKey || value is SystemThemeKey;

Try / catch

try
{
    var ext = (MarkupExtension)converter.ConvertTo(null, culture, value, typeof(MarkupExtension));
}
catch (ArgumentException ex)
{
    // value was not a system key; log and handle non-convertible input
}

Prevention

When it happens

Trigger: Calling TypeConverter.ConvertTo (or TypeDescriptor.GetConverter(new SystemResourceKey(...)).ConvertTo(null, culture, value, destinationType)) with a value that is neither SystemResourceKey nor SystemThemeKey, e.g. passing a raw enum, a string, or a different key type.

Common situations: Custom XAML serialization/markup extension code that walks resource dictionaries and assumes every value is a system key; converters reused with arbitrary keys like DynamicResourceExtension values; refactoring that changed the key type without updating the converter call.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14). Data as JSON: /api/errors/5b9f24e4219eb7ab. Report an issue: GitHub.

Appendix: source

Thrown at src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/SystemKeyConverter.cs:132

            if (destinationType == typeof(MarkupExtension)
                &&
                CanConvertTo(context, destinationType) )
            {
                SystemResourceKeyID keyId;

                // Get the SystemResourceKeyID
                
                if( value is SystemResourceKey )
                {
                    keyId = (value as SystemResourceKey).InternalKey;
                }
                else if( value is SystemThemeKey )
                {
                    keyId = (value as SystemThemeKey).InternalKey;
                }
                else
                {
                    throw new ArgumentException(SR.Format(SR.MustBeOfType, "value", "SystemResourceKey or SystemThemeKey")); 
                }

                // System resource keys can be converted into a MarkupExtension (StaticExtension)
                
                Type keyType = SystemKeyConverter.GetSystemClassType(keyId);

                // Get the value serialization context
                IValueSerializerContext valueSerializerContext = context as IValueSerializerContext;
                if( valueSerializerContext != null )
                {
                    // And from that get a System.Type serializer
                    ValueSerializer typeSerializer = valueSerializerContext.GetValueSerializerFor(typeof(Type));
                    if( typeSerializer != null )
                    {
                        // And use that to create the string-ized class name
                        string systemClassName = typeSerializer.ConvertToString(keyType, valueSerializerContext);

                        // And finally create the StaticExtension.

View on GitHub (pinned to 81131a70a4)