dotnet/reactive · error · ArgumentNullException
Value cannot be null. (Parameter 'invokeHandler')
Error message
Value cannot be null. (Parameter 'invokeHandler')
What it means
The EventPatternSourceBaseInternal constructor requires a non-null invokeHandler delegate, used to raise the event for each element of the sequence. A null delegate is rejected with ArgumentNullException at construction, matching the constructor's documented exception.
Solutions
- Pass a valid Action<Action<TSender,TEventArgs>, EventPattern<TSender,TEventArgs>> delegate.
- Initialize the handler delegate before calling the base constructor.
- Throw a descriptive error or provide a no-op delegate if invocation is legitimately absent.
Example fix
// before
protected MySource(Func<Action<Handler> > lazy)
: base(source, lazy?.Handler) { } // null until initialized
// after
protected MySource(IAsyncObservable<EventPattern<object, EventArgs>> source)
: base(source, (h, e) => Handler(h, e)) { } Defensive patterns
Strategy: validation
Validate before calling
if (invokeHandler is null) throw new ArgumentNullException(nameof(invokeHandler)); // then call the base constructor with invokeHandler
Type guard
static bool HasInvokeHandler(Action<Action<TSender,TEventArgs>, EventPattern<TSender,TEventArgs>>? h) => h is not null;
Try / catch
try { CreateEventPatternSource(source, invokeHandler); }
catch (ArgumentNullException ex) when (ex.ParamName == "invokeHandler")
{ log.LogError("invokeHandler delegate was null"); } Prevention
- Assign invocation delegates before the base constructor runs (pass method groups, not fields assigned later).
- Avoid conditional expressions that can yield null for the handler.
- Keep delegate creation inline in the constructor call.
When it happens
Trigger: Deriving from EventPatternSourceBaseInternal and passing null (or an uninitialized method-group/field delegate) as the invokeHandler constructor argument.
Common situations: Passing a delegate field assigned only later in initialization (null at base-constructor time); refactor renamed the target method so the method group no longer resolves and someone replaced it with null; conditional delegate selection yielding null.
Related errors
- Value cannot be null. (Parameter 'invoke')
- Value cannot be null. (Parameter 'source')
- Value cannot be null. (Parameter 'handler')
- ArgumentNullException(nameof(onNext))
- nameof(condition)
AI-assisted analysis of dotnet/reactive@94b5d5ab91 (2026-09-15).
Data as JSON: /api/errors/93fd7a8287e2d52f.
Report an issue: GitHub.
Appendix: source
Thrown at AsyncRx.NET/System.Reactive.Async/Internal/EventPatternSourceBaseInternal.cs:37
/// avoid a conflict. Work out whether we could in fact just use the type defined in System.Reactive. It's not identical,
/// but perhaps it offers what we need.
/// </remarks>
internal abstract class EventPatternSourceBaseInternal<TSender, TEventArgs>
{
private readonly IAsyncObservable<EventPattern<TSender, TEventArgs>> _source;
private readonly Dictionary<Delegate, Stack<IAsyncDisposable>> _subscriptions;
private readonly Action<Action<TSender, TEventArgs>, /*object,*/ EventPattern<TSender, TEventArgs>> _invokeHandler;
/// <summary>
/// Creates a new event pattern source.
/// </summary>
/// <param name="source">Source sequence to expose as an event.</param>
/// <param name="invokeHandler">Delegate used to invoke the event for each element of the sequence.</param>
/// <exception cref="ArgumentNullException"><paramref name="source"/> or <paramref name="invokeHandler"/> is null.</exception>
protected EventPatternSourceBaseInternal(IAsyncObservable<EventPattern<TSender, TEventArgs>> source, Action<Action<TSender, TEventArgs>, /*object,*/ EventPattern<TSender, TEventArgs>> invokeHandler)
{
_source = source ?? throw new ArgumentNullException(nameof(source));
_invokeHandler = invokeHandler ?? throw new ArgumentNullException(nameof(invokeHandler));
_subscriptions = new Dictionary<Delegate, Stack<IAsyncDisposable>>();
}
/// <summary>
/// Adds the specified event handler, causing a subscription to the underlying source.
/// </summary>
/// <param name="handler">Event handler to add. The same delegate should be passed to the Remove operation in order to remove the event handler.</param>
/// <param name="invoke">Invocation delegate to raise the event in the derived class.</param>
/// <exception cref="ArgumentNullException"><paramref name="handler"/> or <paramref name="invoke"/> is null.</exception>
protected void Add(Delegate handler, Action<TSender, TEventArgs> invoke)
{
if (handler == null)
throw new ArgumentNullException(nameof(handler));
if (invoke == null)
throw new ArgumentNullException(nameof(invoke));
var gate = new object();
var isAdded = false;View on GitHub (pinned to 94b5d5ab91)