dotnet/wpf · error · ArgumentException

SR.Format(SR.CannotConvertStringToType…

Error message

SR.Format(SR.CannotConvertStringToType, keyToken.ToString(), typeof(Key))

What it means

KeyConverter.GetKeyFromString converts a string like 'A' or '5' to a Key. Single characters are mapped to Key.A/Key.D0 ranges only for ASCII letters and digits; any other single-character token (e.g. ',' or '€') that is not handled falls through and throws ArgumentException with CannotConvertStringToType including the token and typeof(Key).

Solutions

  1. Use valid Key names (enum names like 'Enter', 'D1', 'OemComma') or ASCII letters/digits
  2. Verify the shortcut string with a lookup before conversion (KeyConverter.IsValid or Enum.TryParse<Key>)
  3. Fix the config/XAML value to use the documented key token format
  4. Pre-parse with the supported separator '+' and validate each token

Example fix

// before
var key = (Key)new KeyConverter().ConvertFromString(","); // throws
// after
string token = ",";
Key key;
if (!Enum.TryParse(token, ignoreCase: true, out key))
    key = Key.OemComma; // or reject input
Defensive patterns

Strategy: validation

Validate before calling

bool ok = token.Length == 1 ? char.IsAsciiLetterOrDigit(token[0]) : Enum.TryParse<Key>(token, ignoreCase: true, out _);
if (!ok) throw new FormatException($"'{token}' is not a valid Key");

Type guard

static bool IsValidKeyToken(string s) => s.Length == 1 ? char.IsAsciiLetterOrDigit(s[0]) : Enum.TryParse<Key>(s, ignoreCase: true, out _);

Try / catch

try { var key = (Key)new KeyConverter().ConvertFromString(token); }
catch (ArgumentException ex) { log.Error($"Cannot convert '{token}' to Key: {ex.Message}"); }

Prevention

When it happens

Trigger: Calling KeyConverter.ConvertFrom (or ConvertFromInvariantString) with a one-character string that is not an ASCII digit or A–Z letter and is not a named key (e.g. ',', ';', or a non-ASCII character) — within the switch paths where keyToken.Length==1.

Common situations: Parsing keyboard shortcuts from config/XAML with wrong separators (e.g. 'Ctrl+,' semantics assumed), localized key names, or typos like 'Ctrl+Å' that don't map to a Key enum member.

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/0f9eff8016a70be9. Report an issue: GitHub.

Appendix: source

Thrown at src/Microsoft.DotNet.Wpf/src/WindowsBase/System/Windows/Input/KeyConverter.cs:123

            // If the token is empty, we presume "None" as our value but it is a success
            if (keyToken.IsEmpty)
                return Key.None;

            // In case we're dealing with a lowercase character, we uppercase it
            char firstChar = keyToken[0];
            if (firstChar >= 'a' && firstChar <= 'z')
                firstChar ^= (char)0x20;

            // If this is a single-character we're dealing with, match digits/letters
            if (keyToken.Length == 1 && char.IsLetterOrDigit(firstChar))
            {
                // Match an ASCII digit or an ASCII letter (lower/uppercase)
                if (char.IsAsciiDigit(firstChar)) // 0 - 9
                    return Key.D0 + firstChar - '0';
                else if (char.IsAsciiLetterUpper(firstChar)) // A - Z
                    return Key.A + firstChar - 'A';
                else
                    throw new ArgumentException(SR.Format(SR.CannotConvertStringToType, keyToken.ToString(), typeof(Key)));
            }

            // It is a special key or an invalid one, we're gonna find out
            switch (keyToken.Length)
            {
                case 2:
                    // Special path for F1-F9 (switch would take 600 B in code size for no benefit)
                    char secondChar = keyToken[1];
                    if (firstChar == 'F' && (secondChar > '0' && secondChar <= '9'))
                        return Key.F1 + secondChar - '1';
                    // We've got one more special case for Key.Back/Backspace -> "BS"
                    if (firstChar == 'B' && (secondChar is 'S' or 's'))
                        return Key.Back;
                    break;
                case 3:
                    switch (firstChar)
                    {
                        case 'A':

View on GitHub (pinned to 81131a70a4)