dotnet/wpf · error · ArgumentException
SR.HandlerTypeIllegal
Error message
SR.HandlerTypeIllegal
What it means
AddHandler throws ArgumentException when the handler delegate's concrete type does not exactly match routedEvent.HandlerType. Unlike CLR events, routed events require the delegate type to match exactly (e.g. RoutedEventHandler for Click), not just be compatible via assignment. The check is strict equality of the handler's runtime type.
Solutions
- Wrap the method in the exact delegate type: routedEvent.HandlerType, e.g. new RoutedEventHandler(OnClick) for Click.
- Check routedEvent.HandlerType at runtime to see the required delegate type.
- Declare handler variables with the specific delegate type instead of Delegate/Action.
Example fix
// before Delegate h = new MouseButtonEventHandler(OnClick); factory.AddHandler(ButtonBase.ClickEvent, h); // after RoutedEventHandler h = OnClick; factory.AddHandler(ButtonBase.ClickEvent, h);
Defensive patterns
Strategy: type-guard
Validate before calling
if (handler.GetType() != routedEvent.HandlerType)
throw new ArgumentException($"Handler must be {routedEvent.HandlerType.Name}"); Type guard
static bool IsMatchingHandler(RoutedEvent e, Delegate h) => h.GetType() == e.HandlerType;
Try / catch
try { factory.AddHandler(routedEvent, handler); }
catch (ArgumentException) { var typed = Delegate.CreateDelegate(routedEvent.HandlerType, handler.Target, handler.Method); factory.AddHandler(routedEvent, typed); } Prevention
- Declare handler variables with the exact routed-event delegate type.
- Inspect routedEvent.HandlerType before wrapping a method.
- Avoid Delegate/Action variables when calling AddHandler.
When it happens
Trigger: Calling factory.AddHandler(routedEvent, handler) where handler.GetType() != routedEvent.HandlerType — e.g. passing a RoutedEventHandler to an event expecting a MouseButtonEventHandler, or a lambda cast to the wrong delegate type.
Common situations: Reusing one handler method for multiple events and wrapping it in the wrong delegate type; generic or custom delegate declarations that compile but don't match the routed event's HandlerType.
Understand the failure class
Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.
Related errors
- SR.HandlerTypeIllegal
- SR.HandlerTypeIllegal
- ArgumentOutOfRangeException(routedEvent)
- getPage
- InvalidEnumArgumentException: routingStrategy
AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14).
Data as JSON: /api/errors/1e354c5a313f7a1e.
Report an issue: GitHub.
Appendix: source
Thrown at src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/FrameworkElementFactory.cs:310
AddHandler(routedEvent, handler, false);
}
/// <summary>
/// Add an event handler for the given routed event. This action applies to the instances created by this factory
/// </summary>
public void AddHandler(RoutedEvent routedEvent, Delegate handler, bool handledEventsToo)
{
if (_sealed)
{
throw new InvalidOperationException(SR.Format(SR.CannotChangeAfterSealed, "FrameworkElementFactory"));
}
ArgumentNullException.ThrowIfNull(routedEvent);
ArgumentNullException.ThrowIfNull(handler);
if (handler.GetType() != routedEvent.HandlerType)
{
throw new ArgumentException(SR.HandlerTypeIllegal);
}
if (_eventHandlersStore == null)
{
_eventHandlersStore = new EventHandlersStore();
}
_eventHandlersStore.AddRoutedEventHandler(routedEvent, handler, handledEventsToo);
// Keep track of whether we're listening to the loaded or unloaded events;
// if so, we have to trigger a listener in the FE/FCE (as a performance
// optimization).
if ( (routedEvent == FrameworkElement.LoadedEvent)
||(routedEvent == FrameworkElement.UnloadedEvent))
{
HasLoadedChangeHandler = true;
}View on GitHub (pinned to 81131a70a4)