dotnet/reactive · error · ArgumentNullException

Value cannot be null. (Parameter 'onNext')

Error message

Value cannot be null. (Parameter 'onNext')

What it means

The AnonymousObserver constructor throws ArgumentNullException when the onNext action is null. AnonymousObserver powers Observable.Subscribe(onNext, onError, onCompleted); all three callbacks are invoked as the source emits, and the library requires explicit non-null handlers rather than silently ignoring notifications.

Solutions

  1. Supply a real onNext action, e.g. x => Console.WriteLine(x)
  2. If onNext is genuinely unneeded, pass a no-op: _ => { }
  3. Null-check or default the callback before subscribing

Example fix

// before
var sub = source.Subscribe(nextHandler, ex => Log(ex), () => Done()); // nextHandler null
// after
var sub = source.Subscribe(nextHandler ?? (_ => { }), ex => Log(ex), () => Done());
Defensive patterns

Strategy: type-guard

Validate before calling

// C#
Action<int>? onNext = ResolveNext();
if (onNext is null)
    onNext = _ => { };
var sub = source.Subscribe(onNext, ex => Log(ex), () => Done());

Type guard

bool HasNext<T>(Action<T>? a) => a is not null;

Try / catch

try { var sub = source.Subscribe(onNext, onError, onCompleted); }
catch (ArgumentNullException ex) when (ex.ParamName == "onNext")
{
    // supply a default onNext or abort subscription
}

Prevention

When it happens

Trigger: Calling new AnonymousObserver<T>(null, onError, onCompleted) or source.Subscribe(onNext: null, onError, onCompleted) / Subscribe((Action<T>)null, ex => ..., () => ...) with a null onNext while supplying the other two handlers.

Common situations: UI/event handlers where the onNext callback comes from an unset delegate or event field; dynamic subscription builders from config where the next-handler key is missing; refactors that removed the body but kept the null variable.

Related errors


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

Appendix: source

Thrown at Rx.NET/Source/src/System.Reactive/AnonymousObserver.cs:26

    /// Class to create an <see cref="IObserver{T}"/> instance from delegate-based implementations of the On* methods.
    /// </summary>
    /// <typeparam name="T">The type of the elements in the sequence.</typeparam>
    public sealed class AnonymousObserver<T> : ObserverBase<T>
    {
        private readonly Action<T> _onNext;
        private readonly Action<Exception> _onError;
        private readonly Action _onCompleted;

        /// <summary>
        /// Creates an observer from the specified <see cref="IObserver{T}.OnNext(T)"/>, <see cref="IObserver{T}.OnError(Exception)"/>, and <see cref="IObserver{T}.OnCompleted()"/> actions.
        /// </summary>
        /// <param name="onNext">Observer's <see cref="IObserver{T}.OnNext(T)"/> action implementation.</param>
        /// <param name="onError">Observer's <see cref="IObserver{T}.OnError(Exception)"/> action implementation.</param>
        /// <param name="onCompleted">Observer's <see cref="IObserver{T}.OnCompleted()"/> action implementation.</param>
        /// <exception cref="ArgumentNullException"><paramref name="onNext"/> or <paramref name="onError"/> or <paramref name="onCompleted"/> is <c>null</c>.</exception>
        public AnonymousObserver(Action<T> onNext, Action<Exception> onError, Action onCompleted)
        {
            _onNext = onNext ?? throw new ArgumentNullException(nameof(onNext));
            _onError = onError ?? throw new ArgumentNullException(nameof(onError));
            _onCompleted = onCompleted ?? throw new ArgumentNullException(nameof(onCompleted));
        }

        /// <summary>
        /// Creates an observer from the specified <see cref="IObserver{T}.OnNext(T)"/> action.
        /// </summary>
        /// <param name="onNext">Observer's <see cref="IObserver{T}.OnNext(T)"/> action implementation.</param>
        /// <exception cref="ArgumentNullException"><paramref name="onNext"/> is <c>null</c>.</exception>
        public AnonymousObserver(Action<T> onNext)
            : this(onNext, Stubs.Throw, Stubs.Nop)
        {
        }

        /// <summary>
        /// Creates an observer from the specified <see cref="IObserver{T}.OnNext(T)"/> and <see cref="IObserver{T}.OnError(Exception)"/> actions.
        /// </summary>
        /// <param name="onNext">Observer's <see cref="IObserver{T}.OnNext(T)"/> action implementation.</param>

View on GitHub (pinned to 94b5d5ab91)