dotnet/wpf · error · ArgumentException

SR.OnlyAcceptsKeyMessages

Error message

SR.OnlyAcceptsKeyMessages

What it means

This HwndSource member (the keyboard-sink message processing path) accepts only keyboard-related window messages; its switch statement whitelists messages such as WM_KEYDOWN/WM_KEYUP/WM_CHAR/WM_DEADCHAR and throws ArgumentException(SR.OnlyAcceptsKeyMessages) for anything else. It is a contract check that the caller only forwards messages this sink is meant to process.

Solutions

  1. Filter messages before calling: only route WM_KEYDOWN, WM_KEYUP, WM_SYSKEYDOWN, WM_SYSKEYUP, WM_CHAR, WM_DEADCHAR (and siblings the switch allows).
  2. In an AddHook handler, return early (don't call the processor) for messages you don't handle.
  3. Use the public HwndSource pipeline (WndProc) rather than calling internal processing methods with arbitrary messages.

Example fix

// before
void Hook(IntPtr hwnd, int msg, IntPtr w, IntPtr l, ref bool handled)
{
    ProcessKeyboardMessage((WindowMessage)msg); // throws for WM_PAINT
}
// after
void Hook(IntPtr hwnd, int msg, IntPtr w, IntPtr l, ref bool handled)
{
    switch ((WindowMessage)msg)
    {
        case WindowMessage.WM_KEYDOWN:
        case WindowMessage.WM_KEYUP:
        case WindowMessage.WM_CHAR:
            ProcessKeyboardMessage((WindowMessage)msg);
            break;
    }
}
Defensive patterns

Strategy: validation

Validate before calling

static readonly HashSet<WindowMessage> Accepted = new() {
    WindowMessage.WM_KEYDOWN, WindowMessage.WM_KEYUP,
    WindowMessage.WM_SYSKEYDOWN, WindowMessage.WM_SYSKEYUP,
    WindowMessage.WM_CHAR, WindowMessage.WM_DEADCHAR };
if (Accepted.Contains(msg)) ProcessKeyboardMessage(msg);

Try / catch

try
{
    ProcessKeyboardMessage(msg);
}
catch (ArgumentException)
{
    // non-key message reached the keyboard path; ignore
}

Prevention

When it happens

Trigger: Forwarding a non-key WindowMessage (e.g. WM_MOUSEMOVE, WM_PAINT, or an application-defined message) into the sink's keyboard processing method instead of letting the normal WndProc dispatch handle it.

Common situations: Custom AddHook callbacks that forward every message to the sink unfiltered; testing/automation code synthesizing messages and calling the processor directly; forwarding messages from a parent window that include non-key messages.

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/22d4c53bdcae1c8c. Report an issue: GitHub.

Appendix: source

Thrown at src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/InterOp/HwndSource.cs:2092

                        if (AccessKeyManager.IsKeyRegistered(this, text))
                        {
                            AccessKeyManager.ProcessKey(this, text, false);

                            // is it ok not to update _lastKeyboardMessage?
                            return true;
                        }
                    }
                    // these are OK
                    break;

                case WindowMessage.WM_CHAR:
                case WindowMessage.WM_DEADCHAR:
                    // these are OK
                    break;

                default:
                    throw new ArgumentException(SR.OnlyAcceptsKeyMessages);
            }

            // We record the last message that was processed by us.
            // This is also checked in WndProc processing to prevent double processing.
            _lastKeyboardMessage = msg;

            // The bubble will take care of access key processing for this HWND.  Call
            // the IKIS children unless we are in menu mode.
            if (_keyboardInputSinkChildren != null && !IsInExclusiveMenuMode)
            {
                foreach ( HwndSourceKeyboardInputSite childSite in _keyboardInputSinkChildren )
                {
                    if (((IKeyboardInputSite)childSite).Sink.OnMnemonic(ref msg, modifiers))
                        return true;
                }
            }
            return false;
        }

View on GitHub (pinned to 81131a70a4)