dotnet/wpf · error · ArgumentException
SR.HandlerTypeIllegal
Error message
SR.HandlerTypeIllegal
What it means
UIElement.AddHandler throws ArgumentException with SR.HandlerTypeIllegal when the supplied handler delegate is not of a type the routed event considers legal. RoutedEvent.IsLegalHandler checks that the handler's type matches the event's registered handler type (e.g. RoutedEventHandler) or is a compatible delegate. This prevents wiring a delegate with the wrong signature to a routed event, which would fail at invoke time.
Solutions
- Use a handler delegate whose type exactly matches the type the RoutedEvent was registered with (the handlerType argument to RoutedEvent.Register).
- If you intended the generic handler, use RoutedEvent.AddHandler(owner, handler) overload semantics or re-register the event with RoutedEventHandler as its handler type.
- Use the CLR event wrapper (e.g. element.MouseDown += Handler) and let the compiler enforce the delegate type.
- Verify routedEvent.HandlerType at runtime if the event is received dynamically, and construct the handler via Delegate.CreateDelegate with that type.
Example fix
// before
var handler = new EventHandler((s, e) => { });
elem.AddHandler(MyControl.MyCustomEvent, handler); // ArgumentException
// after
var handler = new MyCustomRoutedEventHandler((s, e) => { });
elem.AddHandler(MyControl.MyCustomEvent, handler); Defensive patterns
Strategy: validation
Validate before calling
if (routedEvent == null) throw new ArgumentNullException(nameof(routedEvent));
if (handler == null) throw new ArgumentNullException(nameof(handler));
if (!routedEvent.IsLegalHandler(handler))
throw new ArgumentException($"Handler must be of type {routedEvent.HandlerType} for this routed event."); Type guard
static bool IsLegalFor(RoutedEvent ev, Delegate h) => h != null && ev != null && ev.IsLegalHandler(h);
Try / catch
try { element.AddHandler(routedEvent, handler); }
catch (ArgumentException ex) when (ex.Message.Contains("HandlerTypeIllegal") || ex.ParamName == null) { /* log wrong delegate type, use correct handler type */ } Prevention
- Always use the CLR event +=/-= accessors when available so the compiler enforces the delegate type
- Check the handlerType passed to RoutedEvent.Register when writing custom events
- Never cast delegates across unrelated handler types
When it happens
Trigger: Calling uiElement.AddHandler(routedEvent, handler) where handler is a Delegate whose type is not compatible with routedEvent.HandlerType — e.g. passing a MyCustomEventHandler delegate to an event registered for RoutedEventHandler, or passing a generic/unrelated delegate instance.
Common situations: Developers create a custom routed event with a specific handler type but then attach a generic RoutedEventHandler or a lambda cast to the wrong delegate type; refactors change the handler type of a RoutedEvent.Register call but old call sites still use the old delegate type.
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
- ArgumentOutOfRangeException(routedEvent)
- Can only countersign parts with Digital Signature…
- Duplicates not allowed - signature part already exists.
- ExtendedProperty is already part of the…
- GUID cannot be empty.
AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14).
Data as JSON: /api/errors/ef70d64028022cc3.
Report an issue: GitHub.
Appendix: source
Thrown at src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Generated/UIElement.cs:521
/// </param>
/// <param name="handledEventsToo">
/// Flag indicating whether or not the listener wants to
/// hear about events that have already been handled
/// </param>
public void AddHandler(
RoutedEvent routedEvent,
Delegate handler,
bool handledEventsToo)
{
// VerifyAccess();
ArgumentNullException.ThrowIfNull(routedEvent);
ArgumentNullException.ThrowIfNull(handler);
if (!routedEvent.IsLegalHandler(handler))
{
throw new ArgumentException(SR.HandlerTypeIllegal);
}
EnsureEventHandlersStore();
EventHandlersStore.AddRoutedEventHandler(routedEvent, handler, handledEventsToo);
OnAddHandler(routedEvent, handler);
}
/// <summary>
/// Notifies subclass of a new routed event handler. Note that this is
/// called once for each handler added, but OnRemoveHandler is only called
/// on the last removal.
/// </summary>
internal virtual void OnAddHandler(
RoutedEvent routedEvent,
Delegate handler)
{
}View on GitHub (pinned to 81131a70a4)