dotnet/reactive · error · ArgumentNullException

Value cannot be null. (Parameter 'source')

Error message

Value cannot be null. (Parameter 'source')

What it means

The protected EventPatternSourceBaseInternal constructor requires a non-null source sequence (IAsyncObservable<EventPattern<TSender,TEventArgs>>) since it exposes that sequence as an event. A null source is rejected immediately with ArgumentNullException, as documented by the constructor's <exception> tag.

Solutions

  1. Pass a valid non-null IAsyncObservable as source.
  2. Fix the factory/producer that returned the null source.
  3. Guard in the derived factory before invoking the base constructor and throw a clearer error.

Example fix

// before
public MyEventPatternSource(IAsyncObservable<EventPattern<object, EventArgs>> source)
    : base(source, Invoke) { }
// after
public MyEventPatternSource(IAsyncObservable<EventPattern<object, EventArgs>> source)
    : base(source ?? throw new InvalidOperationException("source observable required"), Invoke) { }
Defensive patterns

Strategy: validation

Validate before calling

if (source is null) throw new ArgumentNullException(nameof(source));
// then construct the derived EventPatternSourceBaseInternal with source

Type guard

static bool HasSource(IAsyncObservable<EventPattern<TSender,TEventArgs>>? s) => s is not null;

Try / catch

try { CreateEventPatternSource(source, invoke); }
catch (ArgumentNullException ex) when (ex.ParamName == "source")
{ log.LogError("event-pattern source observable was null"); }

Prevention

When it happens

Trigger: Calling the base constructor from a derived event-pattern class with a null source — e.g. FromEventPattern-style factory passing a null observable, or a chain like source.Where(...) that returned null.

Common situations: Implementing a custom event bridge class and passing an uninitialized observable field; an upstream factory method returning null; mis-ordered constructor arguments in a derived class.

Related errors


AI-assisted analysis of dotnet/reactive@94b5d5ab91 (2026-09-15). Data as JSON: /api/errors/5b9890d2be51282b. Report an issue: GitHub.

Appendix: source

Thrown at AsyncRx.NET/System.Reactive.Async/Internal/EventPatternSourceBaseInternal.cs:36

    /// TODO: System.Reactive defines an EventPatternSourceBase. I (idg10) renamed this to EventPatternSourceBaseInternal to
    /// 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();

View on GitHub (pinned to 94b5d5ab91)