dotnet/reactive · error · ArgumentNullException

Value cannot be null. (Parameter 'onCompleted')

Error message

Value cannot be null. (Parameter 'onCompleted')

What it means

The AnonymousObserver constructor throws ArgumentNullException when the onCompleted action is null. Along with onNext and onError, the completion callback must be a real delegate because Rx will invoke it when the sequence finishes; null is rejected at construction time.

Solutions

  1. Supply a real onCompleted action, e.g. () => Console.WriteLine("done")
  2. If completion is irrelevant, pass a no-op: () => { }
  3. Default the completion callback before subscribing

Example fix

// before
var sub = source.Subscribe(x => Handle(x), ex => Log(ex), null);
// after
var sub = source.Subscribe(x => Handle(x), ex => Log(ex), () => Done());
Defensive patterns

Strategy: type-guard

Validate before calling

// C#
Action? onCompleted = ResolveCompleted();
if (onCompleted is null)
    onCompleted = () => { };
var sub = source.Subscribe(x => Handle(x), ex => Log(ex), onCompleted);

Type guard

bool HasCompleted(Action? a) => a is not null;

Try / catch

try { var sub = source.Subscribe(onNext, onError, onCompleted); }
catch (ArgumentNullException ex) when (ex.ParamName == "onCompleted")
{
    // supply a no-op completion handler
}

Prevention

When it happens

Trigger: Calling new AnonymousObserver<T>(onNext, onError, null) or source.Subscribe(onNext, onError, onCompleted: null), typically when the completion handler is fetched from a nullable delegate or omitted during refactor.

Common situations: UI subscriptions that only care about values and errors; dynamically composed handlers where the completed callback was never assigned; migration from Subscribe overloads that defaulted handlers to ones that require all three.

Related errors


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

Appendix: source

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

    /// <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>
        /// <param name="onError">Observer's <see cref="IObserver{T}.OnError(Exception)"/> action implementation.</param>
        /// <exception cref="ArgumentNullException"><paramref name="onNext"/> or <paramref name="onError"/> is <c>null</c>.</exception>

View on GitHub (pinned to 94b5d5ab91)