dotnet/reactive · error · ArgumentNullException

Value cannot be null. (Parameter 'observer')

Error message

Value cannot be null. (Parameter 'observer')

What it means

AsyncObserver.Catch<TSource,TException>(observer, handler) builds an observer pair that redirects OnError to the handler's fallback observable. The observer argument is the downstream observer receiving events; passing null leaves the sink nowhere to write, so ArgumentNullException('observer') is thrown first.

Solutions

  1. Create/obtain the observer before wiring the Catch sink
  2. Assert the observer is non-null before calling
  3. Trace where the observer value originates; fix the null-returning source

Example fix

// before
var (sink, disp) = AsyncObserver.Catch<int, TimeoutException>(null, ex => AsyncObservable.Return(ex.StackTrace));
// after
var downstream = AsyncObserver.Create<int>(OnNextAsync, OnErrorAsync, OnCompletedAsync);
var (sink, disp) = AsyncObserver.Catch<int, TimeoutException>(downstream, ex => AsyncObservable.Return(ex.StackTrace));
Defensive patterns

Strategy: validation

Validate before calling

if (observer is null) throw new ArgumentNullException(nameof(observer));

Type guard

bool CanWire<T>(IAsyncObserver<T> observer) => observer != null;

Try / catch

try { var (sink, d) = AsyncObserver.Catch<T, TException>(observer, handler); } catch (ArgumentNullException ex) when (ex.ParamName == "observer") { /* fix observer construction */ }

Prevention

When it happens

Trigger: Calling the (IAsyncObserver, Func<TException, IAsyncObservable>) overload with a null observer, typically when the observer variable was never assigned or a factory returned null.

Common situations: Manually composing observer pipelines where the downstream observer comes from a nullable field, or refactorings that reordered construction so the observer is passed before being created.

Related errors


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

Appendix: source

Thrown at AsyncRx.NET/System.Reactive.Async/Linq/Operators/Catch.cs:110

                var source = enumerator.Current;

                var (sink, inner) = AsyncObserver.Catch(observer, enumerator);

                var subscription = await source.SubscribeSafeAsync(sink).ConfigureAwait(false);

                return StableCompositeAsyncDisposable.Create(subscription, inner);
            });
        }
    }

    public partial class AsyncObserver
    {
        public static (IAsyncObserver<TSource>, IAsyncDisposable) Catch<TSource, TException>(IAsyncObserver<TSource> observer, Func<TException, IAsyncObservable<TSource>> handler)
            where TException : Exception
        {
            if (observer == null)
                throw new ArgumentNullException(nameof(observer));
            if (handler == null)
                throw new ArgumentNullException(nameof(handler));

            return Catch<TSource, TException>(observer, ex => new ValueTask<IAsyncObservable<TSource>>(handler(ex)));
        }

        public static (IAsyncObserver<TSource>, IAsyncDisposable) Catch<TSource, TException>(IAsyncObserver<TSource> observer, Func<TException, ValueTask<IAsyncObservable<TSource>>> handler)
            where TException : Exception
        {
            if (observer == null)
                throw new ArgumentNullException(nameof(observer));
            if (handler == null)
                throw new ArgumentNullException(nameof(handler));

            var subscription = new SingleAssignmentAsyncDisposable();

            var sink = Create<TSource>(
                observer.OnNextAsync,

View on GitHub (pinned to 94b5d5ab91)