dotnet/reactive · error · ArgumentNullException

nameof(onError)

Error message

nameof(onError)

What it means

System.Reactive.Async's Do operator requires a non-null onError callback so that error notifications from the source sequence can be forwarded to the witness observer. Passing null makes it impossible to build the observer delegate, so the library throws ArgumentNullException immediately, before any subscription happens. This is a fail-fast programming-contract check, not a runtime data error.

Solutions

  1. Pass a non-null onError handler; use a no-op such as ex => { } (or ex => Task.CompletedTask for the async overload) if you do not care about errors.
  2. Log the error in onError rather than dropping it, so silent failure is avoided.
  3. Add a null check or default argument at the call site before invoking Do.

Example fix

// before
var observer = Do(src, OnNextAsync, null, OnCompletedAsync);
// after
var observer = Do(src, OnNextAsync, ex => Console.WriteLine(ex), OnCompletedAsync);
Defensive patterns

Strategy: validation

Validate before calling

if (onError == null) onError = ex => { }; // or assert: ArgumentNullException.ThrowIfNull(onError) at your own boundary
var observed = Do(observer, onNext, onError, onCompleted);

Type guard

bool IsValidHandler(Delegate d) => d is not null;

Try / catch

try
{
    var observed = Do(observer, onNext, onError, onCompleted);
}
catch (ArgumentNullException ex) when (ex.ParamName == "onError")
{
    logger.LogWarning("Do() called without an error handler; using no-op");
    var observed = Do(observer, onNext, ex2 => { }, onCompleted);
}

Prevention

When it happens

Trigger: Calling the Do<TSource>(IAsyncObserver<TSource> observer, Func<TSource,Task> onNext, Func<Exception,Task> onError, Func<Task> onCompleted) overload (Do.cs:242) with a null onError argument while the other three arguments are non-null.

Common situations: Developers build handler lambdas conditionally (e.g. only wiring onNext and onCompleted) and pass a null onError; refactoring from the simpler Do(observer, onNext) overload to the full triple-callback overload and forgetting to supply the error handler; interop code that maps an external observer whose error handler is null.

Related errors


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

Appendix: source

Thrown at AsyncRx.NET/System.Reactive.Async/Linq/Operators/Do.cs:242

        public static IAsyncObserver<TSource> Do<TSource>(IAsyncObserver<TSource> observer, Func<ValueTask> onCompleted)
        {
            if (observer == null)
                throw new ArgumentNullException(nameof(observer));
            if (onCompleted == null)
                throw new ArgumentNullException(nameof(onCompleted));

            return Do(observer, Create<TSource>(_ => default, _ => default, onCompleted));
        }

        public static IAsyncObserver<TSource> Do<TSource>(IAsyncObserver<TSource> observer, Func<TSource, ValueTask> onNext, Func<Exception, ValueTask> onError, Func<ValueTask> onCompleted)
        {
            if (observer == null)
                throw new ArgumentNullException(nameof(observer));
            if (onNext == null)
                throw new ArgumentNullException(nameof(onNext));
            if (onError == null)
                throw new ArgumentNullException(nameof(onError));
            if (onCompleted == null)
                throw new ArgumentNullException(nameof(onCompleted));

            return Do(observer, Create(onNext, onError, onCompleted));
        }

        public static IAsyncObserver<TSource> Do<TSource>(IAsyncObserver<TSource> observer, IObserver<TSource> witness)
        {
            if (observer == null)
                throw new ArgumentNullException(nameof(observer));
            if (witness == null)
                throw new ArgumentNullException(nameof(witness));

            return Create<TSource>(
                async x =>
                {
                    try
                    {

View on GitHub (pinned to 94b5d5ab91)