dotnet/reactive · error · ArgumentNullException
ArgumentNullException: addHandler
Error message
ArgumentNullException: addHandler
What it means
FromEventPattern<TSender, TResult>(Action<TypedEventHandler<TSender, TResult>> addHandler, Action<...> removeHandler) converts a WinRT event into an observable, and it throws ArgumentNullException("addHandler") when the addHandler delegate is null. Both handler delegates are required: addHandler attaches the TypedEventHandler when the observable is subscribed.
Solutions
- Pass real add/remove accessor method groups, e.g. (h => target.Event += h, h => target.Event -= h).
- If wiring via reflection, verify GetAddMethod()/Delegate.CreateDelegate results are non-null before calling and throw a clearer error otherwise.
- Check spelling/availability of the WinRT event on the actual runtime type; use the correct overload for non-TypedEventHandler events.
Example fix
// before
Action<TypedEventHandler<Button, object>> add = GetAdd("Click"); // null: bad lookup
Observable.FromEventPattern<Button, object>(add, remove);
// after
var add = new Action<TypedEventHandler<Button, object>>(h => button.Click += h);
var remove = new Action<TypedEventHandler<Button, object>>(h => button.Click -= h);
Observable.FromEventPattern<Button, object>(add, remove); Defensive patterns
Strategy: validation
Validate before calling
if (addHandler == null || removeHandler == null)
throw new InvalidOperationException("FromEventPattern requires both add and remove handlers"); Type guard
bool ValidHandlers<TH>(Action<TH>? add, Action<TH>? remove) => add is not null && remove is not null;
Try / catch
try { obs = Observable.FromEventPattern<TSender, TResult>(add, remove); }
catch (ArgumentNullException ex) when (ex.ParamName == "addHandler") { log.Error("add accessor missing for event wiring"); } Prevention
- Always use method-group/lambdas for +=/-= accessors rather than reflection-derived delegates
- When using reflection, assert GetAddMethod/GetRemoveMethod results before calling Rx
- Prefer the exact overload matching the event's delegate type (TypedEventHandler)
When it happens
Trigger: Calling Observable.FromEventPattern<TSender, TResult>(null, removeHandler) — passing a null add delegate, often from a variable resolved by reflection or string lookup that yielded null.
Common situations: Reflection-based event wiring where the add accessor name is misspelled or the event doesn't exist on the target type; generic wrappers storing add/remove delegates that weren't initialized; ported code where one of the two delegates was dropped.
Related errors
- ArgumentNullException: removeHandler
- ArgumentNullException: conversion
- Value cannot be null. (Parameter 'addHandler')
- Value cannot be null. (Parameter 'removeHandler')
- addHandler
AI-assisted analysis of dotnet/reactive@94b5d5ab91 (2026-09-15).
Data as JSON: /api/errors/624d9d6e2dd07125.
Report an issue: GitHub.
Appendix: source
Thrown at Rx.NET/Source/src/System.Reactive.WindowsRuntime/System.Reactive.Linq/WindowsObservable.Events.cs:33
/// </summary>
[CLSCompliant(false)]
public static partial class WindowsObservable
{
/// <summary>
/// Converts a typed event, conforming to the standard event pattern, to an observable sequence.
/// </summary>
/// <typeparam name="TSender">The type of the sender that raises the event.</typeparam>
/// <typeparam name="TResult">The type of the event data generated by the event.</typeparam>
/// <param name="addHandler">Action that attaches the given event handler to the underlying .NET event.</param>
/// <param name="removeHandler">Action that detaches the given event handler from the underlying .NET event.</param>
/// <returns>The observable sequence that contains data representations of invocations of the underlying typed event.</returns>
/// <exception cref="ArgumentNullException"><paramref name="addHandler"/> or <paramref name="removeHandler"/> is null.</exception>
/// <seealso cref="ToEventPattern"/>
public static IObservable<EventPattern<TSender, TResult>> FromEventPattern<TSender, TResult>(Action<TypedEventHandler<TSender, TResult>> addHandler, Action<TypedEventHandler<TSender, TResult>> removeHandler)
{
if (addHandler == null)
{
throw new ArgumentNullException(nameof(addHandler));
}
if (removeHandler == null)
{
throw new ArgumentNullException(nameof(removeHandler));
}
return Observable.Create<EventPattern<TSender, TResult>>(observer =>
{
var h = new TypedEventHandler<TSender, TResult>((sender, args) =>
{
observer.OnNext(new EventPattern<TSender, TResult>(sender, args));
});
addHandler(h);
return () =>
{View on GitHub (pinned to 94b5d5ab91)