AvaloniaUI/Avalonia · error · InvalidCastException
eventArgsType must be derived from RoutedEventArgs.
Error message
eventArgsType must be derived from RoutedEventArgs.
What it means
Thrown by the RoutedEvent constructor when the eventArgsType argument does not derive from RoutedEventArgs. RoutedEvent is the metadata object backing Avalonia's tunneling/bubbling routed-event system, and every routed event must carry strongly-typed EventArgs that inherit from RoutedEventArgs so the routing infrastructure can dispatch and cast them safely. Passing a non-derived Type (e.g. plain EventArgs, or a custom class that forgot the base) violates that contract at registration time.
Source
Thrown at src/Avalonia.Base/Interactivity/RoutedEvent.cs:31
public class RoutedEvent
{
private readonly LightweightSubject<(object, RoutedEventArgs)> _raised = new();
private readonly LightweightSubject<RoutedEventArgs> _routeFinished = new();
public RoutedEvent(
string name,
RoutingStrategies routingStrategies,
Type eventArgsType,
Type ownerType)
{
name = name ?? throw new ArgumentNullException(nameof(name));
eventArgsType = eventArgsType ?? throw new ArgumentNullException(nameof(name));
ownerType = ownerType ?? throw new ArgumentNullException(nameof(name));
if (!typeof(RoutedEventArgs).IsAssignableFrom(eventArgsType))
{
throw new InvalidCastException("eventArgsType must be derived from RoutedEventArgs.");
}
EventArgsType = eventArgsType;
Name = name;
OwnerType = ownerType;
RoutingStrategies = routingStrategies;
}
public Type EventArgsType { get; }
public string Name { get; }
public Type OwnerType { get; }
public RoutingStrategies RoutingStrategies { get; }
public bool HasRaisedSubscriptions => _raised.HasObservers;
View on GitHub (pinned to 11c5427268)
Solutions
- Change the eventArgsType to a class that derives from RoutedEventArgs (create a custom subclass if needed).
- If using RoutedEvent.Register<TEventArgs>(...), ensure TEventArgs : RoutedEventArgs.
- Verify the Type at the call site with typeof(RoutedEventArgs).IsAssignableFrom(eventArgsType) before registration.
Example fix
// before
var evt = new RoutedEvent("Tap", RoutingStrategies.Bubble, typeof(EventArgs), typeof(MyControl));
// after
public class TapEventArgs : RoutedEventArgs { /* ... */ }
var evt = new RoutedEvent("Tap", RoutingStrategies.Bubble, typeof(TapEventArgs), typeof(MyControl)); Defensive patterns
Strategy: type-guard
Validate before calling
static bool IsRoutedEventArgsArgs(Type t) => typeof(RoutedEventArgs).IsAssignableFrom(t);
// usage
if (!IsRoutedEventArgsArgs(eventArgsType))
throw new InvalidOperationException($"{eventArgsType} must derive from RoutedEventArgs.");
var evt = new RoutedEvent(name, routingStrategies, eventArgsType, ownerType); Type guard
// Prefer the generic registration helper which enforces the constraint at compile time:
// RoutedEvent.Register<TEventArgs>("name", RoutingStrategies.Bubble, typeof(Owner))
// where TEventArgs : RoutedEventArgs
static RoutedEvent RegisterSafe<TArgs>(string name, RoutingStrategies rs, Type owner)
where TArgs : RoutedEventArgs
=> RoutedEvent.Register<TArgs>(name, rs, owner); Prevention
- Use the generic RoutedEvent.Register<TEventArgs> overload so the compiler enforces the RoutedEventArgs constraint.
- If passing Type reflectively, validate with IsAssignableFrom before registration.
- Keep all custom event-arg classes in a single folder inheriting from RoutedEventArgs to avoid copy-paste mistakes.
When it happens
Trigger: Calling `new RoutedEvent(name, routingStrategies, eventArgsType, ownerType)` or the `RoutedEvent.Register(...)` helper where `eventArgsType` is a Type that is not assignable to `typeof(RoutedEventArgs)`. Also fires if reflection or a generic registration helper forwards an unconstrained Type argument.
Common situations: Creating a custom routed event for a control and accidentally passing `typeof(EventArgs)` instead of a RoutedEventArgs-derived type. Copy-pasting a RoutedEvent.Register call and forgetting to update the generic/eventArgsType argument. Using an interop/event-args class from another framework that does not inherit from Avalonia's RoutedEventArgs.
Related errors
- 'name' may not contain periods.
- Property '{property.Name} not registered on '{o.GetType()}
- Cannot register a non-attached property as attached.
- Invalid array type
- NameScope is completed, no further registrations are allowed
AI-assisted analysis of AvaloniaUI/Avalonia@11c5427268 (2026-08-13).
Data as JSON: /api/errors/c7229003451368a0.
Report an issue: GitHub.