dotnet/reactive · error · ArgumentNullException

ArgumentNullException(nameof(onCompleted))

Error message

ArgumentNullException(nameof(onCompleted))

What it means

This Do overload validates the onError callback passed as a side-effect observer action; null would make the tap unable to react to errors. The exception is thrown eagerly at operator-assembly time, not at subscription time. Fix: provide a non-null Action<Exception>, or use the Do overload that omits the error handler.

Solutions

  1. Pass a real Action, using a no-op () => { } if no work is needed
  2. Default the handler before composition: handler ?? (() => { })
  3. Fix the configuration/DI wiring that should have provided the handler

Example fix

// before
Action onCompleted = null;
var res = src.Do(onCompleted); // throws
// after
var res = src.Do(onCompleted ?? (() => { }));
Defensive patterns

Strategy: validation

Validate before calling

if (onCompleted is null) onCompleted = () => { };
var res = source.Do(onCompleted);

Type guard

static bool IsValidHandler(Action h) => h is not null;

Try / catch

try { var res = source.Do(onCompleted); }
catch (ArgumentNullException ex) when (ex.ParamName == "onCompleted") { /* fall back to no-op */ }

Prevention

When it happens

Trigger: Calling source.Do(onCompleted) with a null Action, e.g. an unassigned completion-handler field or a null method-group conversion failure.

Common situations: Optional teardown callbacks that default to null; forwarding an uninitialized parameter; configuration wiring that skipped the handler.

Related errors


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

Appendix: source

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

        public static IAsyncObservable<TSource> Do<TSource>(this IAsyncObservable<TSource> source, Action<Exception> onError)
        {
            if (source == null)
                throw new ArgumentNullException(nameof(source));
            if (onError == null)
                throw new ArgumentNullException(nameof(onError));

            return Create(
                source,
                onError,
                static (source, onError, target) => source.SubscribeSafeAsync(AsyncObserver.Do(target, onError)));
        }

        public static IAsyncObservable<TSource> Do<TSource>(this IAsyncObservable<TSource> source, Action onCompleted)
        {
            if (source == null)
                throw new ArgumentNullException(nameof(source));
            if (onCompleted == null)
                throw new ArgumentNullException(nameof(onCompleted));

            return Create(
                source,
                onCompleted,
                static (source, onCompleted, target) => source.SubscribeSafeAsync(AsyncObserver.Do(target, onCompleted)));
        }

        public static IAsyncObservable<TSource> Do<TSource>(this IAsyncObservable<TSource> source, Action<TSource> onNext, Action<Exception> onError, Action onCompleted)
        {
            if (source == null)
                throw new ArgumentNullException(nameof(source));
            if (onNext == null)
                throw new ArgumentNullException(nameof(onNext));
            if (onError == null)
                throw new ArgumentNullException(nameof(onError));
            if (onCompleted == null)
                throw new ArgumentNullException(nameof(onCompleted));

View on GitHub (pinned to 94b5d5ab91)