dotnet/wpf · error · NotSupportedException

SR.Format(SR.Unsupported_Modifier, modifier.ToString())

Error message

SR.Format(SR.Unsupported_Modifier, modifier.ToString())

What it means

ModifierKeysConverter.ConvertFrom parses modifier-key tokens into a ModifierKeys value. Recognized tokens are Ctrl/Control, Win/Windows, Alt, and Shift (case-insensitive); any other token reaches the switch discard arm and throws NotSupportedException with Unsupported_Modifier naming the offending token.

Solutions

  1. Use supported tokens only: Ctrl, Control, Win, Windows, Alt, Shift
  2. Normalize aliases before conversion (map 'Meta'/'Cmd' to 'Control' or 'Windows')
  3. Pre-validate each '+'-separated token against the supported list and report a friendly error
  4. Use ModifierKeysConverter.ConvertToString output as the canonical round-trip format

Example fix

// before
var mk = (ModifierKeys)new ModifierKeysConverter().ConvertFromString("Cmd"); // throws
// after
string token = "Cmd";
token = token.Equals("Cmd", StringComparison.OrdinalIgnoreCase) ? "Control" : token;
var mk = (ModifierKeys)new ModifierKeysConverter().ConvertFromString(token);
Defensive patterns

Strategy: validation

Validate before calling

string[] supported = { "Ctrl","Control","Win","Windows","Alt","Shift" };
bool ok = supported.Contains(token, StringComparer.OrdinalIgnoreCase);
if (!ok) throw new FormatException($"Unsupported modifier: {token}");

Type guard

static bool IsSupportedModifier(string s) => s is "Ctrl" or "Control" or "Win" or "Windows" or "Alt" or "Shift" ||
    new[]{"ctrl","control","win","windows","alt","shift"}.Contains(s.ToLowerInvariant());

Try / catch

try { var mk = (ModifierKeys)new ModifierKeysConverter().ConvertFromString(token); }
catch (NotSupportedException ex) { log.Error($"Unsupported modifier token: {ex.Message}"); }

Prevention

When it happens

Trigger: Calling ConvertFrom/ConvertFromString with a gesture or settings string containing an unrecognized modifier such as 'Meta', 'Cmd', 'Super', or a misspelling like 'Shft', typically from '+'-separated gesture strings.

Common situations: Porting shortcuts from macOS/other frameworks ('Cmd+X'), user-edited hotkey configs, localization of key names, or migrating keybinding settings across platforms.

Understand the failure class

Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.

Related errors


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

Appendix: source

Thrown at src/Microsoft.DotNet.Wpf/src/WindowsBase/System/Windows/Input/ModifierKeysConverter.cs:83

            ModifierKeys modifiers = ModifierKeys.None;
            foreach (Range token in modifiersToken.Split('+'))
            {
                ReadOnlySpan<char> modifier = modifiersToken[token].Trim();

                // This would be a case where we have a token like "Ctrl + " for example,
                // which itself is invalid but we choose to support this malformed behaviour.
                if (modifier.IsEmpty)
                    break;

                modifiers |= modifier switch
                {
                    _ when modifier.Equals("Ctrl", StringComparison.OrdinalIgnoreCase) => ModifierKeys.Control,
                    _ when modifier.Equals("Control", StringComparison.OrdinalIgnoreCase) => ModifierKeys.Control,
                    _ when modifier.Equals("Win", StringComparison.OrdinalIgnoreCase) => ModifierKeys.Windows,
                    _ when modifier.Equals("Windows", StringComparison.OrdinalIgnoreCase) => ModifierKeys.Windows,
                    _ when modifier.Equals("Alt", StringComparison.OrdinalIgnoreCase) => ModifierKeys.Alt,
                    _ when modifier.Equals("Shift", StringComparison.OrdinalIgnoreCase) => ModifierKeys.Shift,
                    _ => throw new NotSupportedException(SR.Format(SR.Unsupported_Modifier, modifier.ToString()))
                };
            }

            return modifiers;
        }

        /// <summary>
        /// Converts a <paramref name="value"/> of <see cref="ModifierKeys"/> to its <see langword="string"/> represensation.
        /// </summary>
        /// <param name="context">Serialization Context</param>
        /// <param name="culture">Culture Info</param>
        /// <param name="value">ModifierKeys value</param>
        /// <param name="destinationType">Type to Convert</param>
        /// <returns>A <see langword="string"/> representing the <see cref="ModifierKeys"/> specified by <paramref name="value"/>.</returns>
        public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
        {
            ArgumentNullException.ThrowIfNull(destinationType);

View on GitHub (pinned to 81131a70a4)