stride3d/stride · error · ArgumentNullException

Value cannot be null. (Parameter 'handler')

Error message

Value cannot be null. (Parameter 'handler')

What it means

EventManager.RegisterClassHandler<T> requires a non-null handler delegate; class handlers are stored as RoutedEventHandlerInfo and invoked during routing, so a null handler is invalid. Fail-fast ArgumentNullException thrown before any state is mutated.

Solutions

  1. Pass a valid EventHandler<T> delegate; verify the handler method exists and matches the generic RoutedEventArgs subtype
  2. If the handler is resolved dynamically, null-check before registering and log/skip otherwise
  3. Remove the registration call entirely if the handler no longer exists

Example fix

// before
EventHandler<RoutedEventArgs> h = ResolveHandler(); // may be null
EventManager.RegisterClassHandler(typeof(Button), Button.ClickEvent, h);
// after
var h = ResolveHandler() ?? throw new InvalidOperationException("Click handler missing");
EventManager.RegisterClassHandler(typeof(Button), Button.ClickEvent, h);
Defensive patterns

Strategy: validation

Validate before calling

if (handler == null) throw new InvalidOperationException("RegisterClassHandler requires a non-null handler");

Type guard

static bool HasHandler<T>(EventHandler<T> h) where T : RoutedEventArgs => h != null;

Try / catch

try { EventManager.RegisterClassHandler<T>(classType, evt, handler); }
catch (ArgumentNullException ex) when (ex.ParamName == "handler") { logger.LogWarning("Skipping class handler registration: handler was null"); }

Prevention

When it happens

Trigger: Calling EventManager.RegisterClassHandler<T>(classType, routedEvent, null), e.g. when the handler method reference is resolved via reflection and the method is missing, or a variable holding the delegate was never assigned.

Common situations: Renaming or deleting a handler method while a registration still references it; reflection-based lookup returning null; conditional code paths that leave the delegate unassigned.

Related errors


AI-assisted analysis of stride3d/stride@96fad776d2 (2026-09-14). Data as JSON: /api/errors/6b5d32fb84aec745. Report an issue: GitHub.

Appendix: source

Thrown at sources/engine/Stride.UI/Events/EventManager.cs:79

            }

            return types.Where(t => OwnerToEvents.ContainsKey(t)).SelectMany(t => OwnerToEvents[t].Values).ToArray();
        }

        /// <summary>
        /// Registers a class handler for a particular routed event, with the option to handle events where event data is already marked handled.
        /// </summary>
        /// <param name="classType">The type of the class that is declaring class handling.</param>
        /// <param name="routedEvent">The routed event identifier of the event to handle.</param>
        /// <param name="handler">A reference to the class handler implementation.</param>
        /// <param name="handledEventsToo">true to invoke this class handler even if arguments of the routed event have been marked as handled; 
        /// false to retain the default behavior of not invoking the handler on any marked-handled event.</param>
        /// <exception cref="ArgumentNullException"><paramref name="classType"/>, <paramref name="routedEvent"/>, or <paramref name="handler"/> is null.</exception>
        public static void RegisterClassHandler<T>(Type classType, RoutedEvent<T> routedEvent, EventHandler<T> handler, bool handledEventsToo = false) where T : RoutedEventArgs
        {
            if (classType == null) throw new ArgumentNullException(nameof(classType));
            if (routedEvent == null) throw new ArgumentNullException(nameof(routedEvent));
            if (handler == null) throw new ArgumentNullException(nameof(handler));

            lock(SyncRoot)
            {
                if (!ClassesToClassHandlers.ContainsKey(classType))
                    ClassesToClassHandlers[classType] = new Dictionary<RoutedEvent, RoutedEventHandlerInfo>();

                ClassesToClassHandlers[classType][routedEvent] = new RoutedEventHandlerInfo<T>(handler, handledEventsToo); 
            }
        }

        /// <summary>
        /// Get the class handler for the class <paramref name="classType"/> and routed event <paramref name="routedEvent"/>.
        /// </summary>
        /// <param name="classType">The type of the class that is handling the event.</param>
        /// <param name="routedEvent">The routed event to handle</param>
        /// <returns>The class handler</returns>
        /// <exception cref="ArgumentNullException"><paramref name="classType"/>, or <paramref name="routedEvent"/> is null.</exception>
        internal static RoutedEventHandlerInfo GetClassHandler(Type classType, RoutedEvent routedEvent)

View on GitHub (pinned to 96fad776d2)