dotnet/reactive · error · ArgumentNullException

Thrown when observer is null (ArgumentNullException, param…

Error message

Thrown when observer is null (ArgumentNullException, param name: observer)

What it means

The Do(source, observer) overload requires a non-null IObserver<TSource> and throws ArgumentNullException with parameter name 'observer'. The observer's OnNext, OnError, and OnCompleted methods are captured and invoked during enumeration, so null is rejected eagerly at the call site.

Solutions

  1. Supply a real IObserver implementation or a test double before calling Do
  2. Default to a no-op observer: `observer ??= NullObserver<T>.Instance;` (or an anonymous implementation)
  3. Fix the DI/registry wiring that yields a null observer
  4. Guard the stage: only add Do(observer) when observer != null

Example fix

// before
var result = source.Do(null);
// after
var result = source.Do(new AnonymousObserver<T>(x => Log(x)));
// or
observer ??= new NopObserver<T>();
var result = source.Do(observer);
Defensive patterns

Strategy: validation

Validate before calling

if (observer is null) throw new InvalidOperationException("Observer must be registered before composing Do.");
// or default:
// if (observer is null) observer = new NopObserver<T>();

Type guard

static bool HasObserver<T>(IObserver<T>? o) => o is not null;

Try / catch

try { var result = source.Do(observer!); ... }
catch (ArgumentNullException ex) when (ex.ParamName == "observer") { Log("observer missing; attaching no-op observer"); result = source; }

Prevention

When it happens

Trigger: `source.Do(null)`; an observer resolved from DI or a registry that returned null; a field/property of observer type never assigned before pipeline construction.

Common situations: Observer registrations missing in the DI container; test doubles (mock observers) not initialized; conditional observer attachment where the observer is null in some environments.

Related errors


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

Appendix: source

Thrown at Ix.NET/Source/System.Interactive/System/Linq/Operators/Do.cs:104

            if (onCompleted == null)
                throw new ArgumentNullException(nameof(onCompleted));

            return DoCore(source, onNext, onError, onCompleted);
        }

        /// <summary>
        /// Lazily invokes observer methods for each value in the sequence, and upon successful or exceptional termination.
        /// </summary>
        /// <typeparam name="TSource">Source sequence element type.</typeparam>
        /// <param name="source">Source sequence.</param>
        /// <param name="observer">Observer to invoke notification calls on.</param>
        /// <returns>Sequence exhibiting the side-effects of observer method invocation upon enumeration.</returns>
        public static IEnumerable<TSource> Do<TSource>(this IEnumerable<TSource> source, IObserver<TSource> observer)
        {
            if (source == null)
                throw new ArgumentNullException(nameof(source));
            if (observer == null)
                throw new ArgumentNullException(nameof(observer));

            return DoCore(source, observer.OnNext, observer.OnError, observer.OnCompleted);
        }

        private static IEnumerable<TSource> DoCore<TSource>(IEnumerable<TSource> source, Action<TSource> onNext, Action<Exception> onError, Action onCompleted)
        {
            using var e = source.GetEnumerator();

            while (true)
            {
                TSource current;
                try
                {
                    if (!e.MoveNext())
                        break;

                    current = e.Current;
                }

View on GitHub (pinned to 94b5d5ab91)