dotnet/reactive · error · ArgumentNullException
Value cannot be null. (Parameter 'removeHandler')
Error message
Value cannot be null. (Parameter 'removeHandler')
What it means
Observable.FromEventPattern(addHandler, removeHandler) also requires a non-null removeHandler so the subscription can detach on dispose. A null removeHandler throws ArgumentNullException at call time.
Solutions
- Pass a non-null detach lambda, e.g. h => target.Event -= h
- Verify reflection code obtains both GetAddMethod and GetRemoveMethod delegates
- Check wrapper methods for argument transposition that leaves removeHandler null
Example fix
// before Observable.FromEventPattern(h => target.Click += h, null); // after Observable.FromEventPattern(h => target.Click += h, h => target.Click -= h);
Defensive patterns
Strategy: validation
Validate before calling
if (addHandler == null || removeHandler == null) throw new ArgumentNullException(removeHandler == null ? nameof(removeHandler) : nameof(addHandler)); var seq = Observable.FromEventPattern(addHandler, removeHandler);
Type guard
static bool HasRemoveHandler(Action<EventHandler> remove) => remove is not null;
Try / catch
try
{
var seq = Observable.FromEventPattern(addHandler, removeHandler);
}
catch (ArgumentNullException ex) when (ex.ParamName == "removeHandler")
{
throw new InvalidOperationException("Event remove accessor was not resolved", ex);
} Prevention
- Always pair add and remove lambdas next to each other in code review
- Check reflection code for both accessors before constructing delegates
- Avoid storing the pair in partially initialized state; construct both or neither
When it happens
Trigger: Calling FromEventPattern(Action<EventHandler>, Action<EventHandler>) with a null second argument while addHandler is non-null.
Common situations: Reflection-resolved remove accessor that was null; partially initialized helper classes where only the add delegate was assigned; copy-paste code that set addHandler twice.
Related errors
- Value cannot be null. (Parameter 'addHandler')
- observer
- scheduler (Value cannot be null)
- action (Value cannot be null)
- scheduler (Value cannot be null)
AI-assisted analysis of dotnet/reactive@94b5d5ab91 (2026-09-15).
Data as JSON: /api/errors/ec11731fcefb6c08.
Report an issue: GitHub.
Appendix: source
Thrown at Rx.NET/Source/src/System.Reactive/Linq/Observable.Events.cs:57
/// making the Subscribe or Dispose call, respectively.
/// </para>
/// <para>
/// It's recommended to lift FromEventPattern calls outside event stream query expressions due to the free-threaded nature of Reactive Extensions. Doing so
/// makes the captured SynchronizationContext predictable. This best practice also reduces clutter of bridging code inside queries, making the query expressions
/// more concise and easier to understand.
/// </para>
/// </remarks>
/// <seealso cref="ToEventPattern"/>
public static IObservable<EventPattern<object>> FromEventPattern(Action<EventHandler> addHandler, Action<EventHandler> removeHandler)
{
if (addHandler == null)
{
throw new ArgumentNullException(nameof(addHandler));
}
if (removeHandler == null)
{
throw new ArgumentNullException(nameof(removeHandler));
}
return s_impl.FromEventPattern(addHandler, removeHandler);
}
/// <summary>
/// Converts a .NET event, conforming to the standard .NET event pattern based on <see cref="EventHandler"/>, to an observable sequence.
/// Each event invocation is surfaced through an OnNext message in the resulting sequence.
/// For conversion of events that don't conform to the standard .NET event pattern, use any of the FromEvent overloads instead.
/// </summary>
/// <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>
/// <param name="scheduler">The scheduler to run the add and remove event handler logic on.</param>
/// <returns>The observable sequence that contains data representations of invocations of the underlying .NET event.</returns>
/// <exception cref="ArgumentNullException"><paramref name="addHandler"/> or <paramref name="removeHandler"/> or <paramref name="scheduler"/> is null.</exception>
/// <remarks>
/// <para>
/// Add and remove handler invocations are made whenever the number of observers grows beyond zero.View on GitHub (pinned to 94b5d5ab91)