stride3d/stride · error · ArgumentNullException
Value cannot be null. (Parameter 'ownerType')
Error message
Value cannot be null. (Parameter 'ownerType')
What it means
RegisterRoutedEvent<T> requires a non-null ownerType; the owner type scopes the event name and is used for duplicate detection and later GetRoutedEvent lookups. Null is rejected immediately with ArgumentNullException.
Solutions
- Pass typeof(YourControl) of the class that owns the event
- If the type is resolved dynamically, null-check the Type before registering
- Fix the type name/assembly string in Type.GetType calls
Example fix
// before
var owner = Type.GetType("MyApp.MyControl"); // null if wrong assembly
EventManager.RegisterRoutedEvent<RoutedEventArgs>("Tap", RoutingStrategy.Bubble, owner);
// after
EventManager.RegisterRoutedEvent<RoutedEventArgs>("Tap", RoutingStrategy.Bubble, typeof(MyApp.MyControl)); Defensive patterns
Strategy: validation
Validate before calling
if (ownerType == null) throw new InvalidOperationException("Owner type must be provided"); Type guard
static bool ValidOwnerType(Type t) => t != null && !t.IsGenericTypeDefinition;
Try / catch
try { return EventManager.RegisterRoutedEvent<T>(name, strategy, ownerType); }
catch (ArgumentNullException ex) when (ex.ParamName == "ownerType") { logger.LogError(ex, "Owner type was null for event {Name}", name); throw; } Prevention
- Always pass typeof(YourControl)
- Avoid Type.GetType with hardcoded strings; prefer direct type references
- Register events inside the owning class's static constructor
When it happens
Trigger: Calling EventManager.RegisterRoutedEvent<T>(name, routingStrategy, null), e.g. passing typeof(...) of a generic type parameter resolved at runtime that came back null, or a Type field not yet initialized.
Common situations: Reflection-based Type.GetType with a bad assembly-qualified name returning null; passing a variable instead of typeof(YourControl); static initialization order issues.
Related errors
- Value cannot be null. (Parameter 'routedEvent')
- Value cannot be null. (Parameter 'handler')
- Value cannot be null. (Parameter 'name')
- A routed event named
- The routed event cannot be changed while the event is being…
AI-assisted analysis of stride3d/stride@96fad776d2 (2026-09-14).
Data as JSON: /api/errors/c585ea6ea61ecc0d.
Report an issue: GitHub.
Appendix: source
Thrown at sources/engine/Stride.UI/Events/EventManager.cs:132
private static readonly Dictionary<Type, Dictionary<RoutedEvent, RoutedEventHandlerInfo>> ClassesToClassHandlers = new Dictionary<Type, Dictionary<RoutedEvent, RoutedEventHandlerInfo>>();
/// <summary>
/// Registers a new routed event.
/// </summary>
/// <param name="name">The name of the routed event. The name must be unique within the owner type (base class included) and cannot be null or an empty string.</param>
/// <param name="routingStrategy">The routing strategy of the event as a value of the enumeration.</param>
/// <param name="ownerType">The owner class type of the routed event. This cannot be null.</param>
/// <returns>The identifier for the newly registered routed event.
/// This identifier object can now be stored as a static field in a class and then used as a parameter for methods that attach handlers to the event.
/// The routed event identifier is also used for other event system APIs.</returns>
/// <exception cref="ArgumentNullException"><paramref name="name"/> or <paramref name="ownerType"/> is null.</exception>
/// <exception cref="InvalidOperationException">This exception is thrown if a routed event of name <paramref name="name"/> already exists for type <paramref name="ownerType"/> and parents.
/// </exception>
public static RoutedEvent<T> RegisterRoutedEvent<T>(string name, RoutingStrategy routingStrategy, Type ownerType) where T: RoutedEventArgs
{
if (name == null) throw new ArgumentNullException(nameof(name));
if (ownerType == null) throw new ArgumentNullException(nameof(ownerType));
if (GetRoutedEvent(ownerType, name) != null)
throw new InvalidOperationException("A routed event named '" + name + "' already exists in provided owner type '" + ownerType + "' or base classes.");
var newRoutedEvent = new RoutedEvent<T> { Name = name, OwnerType = ownerType, RoutingStrategy = routingStrategy, };
lock(SyncRoot)
{
RoutedEvents.Add(newRoutedEvent);
if (!OwnerToEvents.ContainsKey(ownerType))
OwnerToEvents[ownerType] = new Dictionary<string, RoutedEvent>();
OwnerToEvents[ownerType][name] = newRoutedEvent;
}
return newRoutedEvent;
}
View on GitHub (pinned to 96fad776d2)