stride3d/stride · error · ArgumentNullException
Value cannot be null. (Parameter 'name')
Error message
Value cannot be null. (Parameter 'name')
What it means
RegisterRoutedEvent<T> requires a non-null event name because the name is part of the routed event's identity used for lookups (GetRoutedEvent) and duplicate detection. A null name is rejected with ArgumentNullException before any registration state changes.
Solutions
- Pass a literal or guaranteed-initialized const string as the event name
- Null-check any dynamically sourced name before calling RegisterRoutedEvent
- Verify static field initialization order so the name constant is assigned first
Example fix
// before string evtName = LoadEventName(); var evt = EventManager.RegisterRoutedEvent<RoutedEventArgs>(evtName, RoutingStrategy.Bubble, typeof(MyControl)); // after string evtName = LoadEventName() ?? "MyCustomEvent"; var evt = EventManager.RegisterRoutedEvent<RoutedEventArgs>(evtName, RoutingStrategy.Bubble, typeof(MyControl));
Defensive patterns
Strategy: validation
Validate before calling
if (string.IsNullOrEmpty(name)) throw new InvalidOperationException("Event name must be a non-empty string"); Type guard
static bool ValidEventName(string name) => !string.IsNullOrWhiteSpace(name);
Try / catch
try { return EventManager.RegisterRoutedEvent<T>(name, strategy, ownerType); }
catch (ArgumentNullException ex) { throw new InvalidOperationException($"Bad routed event name '{name}'", ex); } Prevention
- Use const string literals for event names
- Avoid sourcing event names from config or reflection without validation
- Register events in static constructors with fixed names
When it happens
Trigger: Calling EventManager.RegisterRoutedEvent<T>(null, routingStrategy, ownerType), usually via a name constant that is null or a config-driven name that failed to load.
Common situations: Constants/resource files not loaded at static-ctor time; reflection reading an attribute property that defaults to null; refactoring that removed the string literal.
Related errors
- Value cannot be null. (Parameter 'routedEvent')
- Value cannot be null. (Parameter 'handler')
- Value cannot be null. (Parameter 'ownerType')
- 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/073453ae60c6f1d8.
Report an issue: GitHub.
Appendix: source
Thrown at sources/engine/Stride.UI/Events/EventManager.cs:131
}
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)