dotnet/reactive · error · ArgumentNullException

Value cannot be null. (Parameter 'observer')

Error message

Value cannot be null. (Parameter 'observer')

What it means

The AsyncObserver.SelectMany factory (observer-side overload taking IAsyncObserver<TResult> and a Func<TSource, IAsyncObservable<TResult>> selector) throws ArgumentNullException because the observer parameter was null. This overload adapts a downstream observer into a SelectMany pipeline; without an observer there is nothing to forward events to, so construction fails immediately.

Solutions

  1. Pass a valid IAsyncObserver<TResult> instance as the first argument.
  2. If composing, verify the upstream expression producing the observer (e.g. AsyncObserver.Create...) actually returned non-null.
  3. Use the higher-level AsyncObservable.SelectMany on the observable instead of manually wiring observer-side factories.
  4. Assert the observer argument at the call site before invoking AsyncObserver.SelectMany.

Example fix

// before
var (obs, disp) = AsyncObserver.SelectMany<TSource, TResult>(null, x => inner);

// after
var downstream = AsyncObserver.Create<TResult>(onNextAsync, onErrorAsync, onCompletedAsync);
var (obs, disp) = AsyncObserver.SelectMany(downstream, x => inner);
Defensive patterns

Strategy: validation

Validate before calling

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

Type guard

static bool IsValidObserverArgs<TSource, TResult>(
    IAsyncObserver<TResult> observer,
    Func<TSource, IAsyncObservable<TResult>> selector)
    => observer is not null && selector is not null;

Try / catch

try
{
    var (obs, disp) = AsyncObserver.SelectMany(observer, selector);
}
catch (ArgumentNullException ex) when (ex.ParamName == "observer")
{
    observer = AsyncObserver.Create<TResult>(...); // substitute a no-op observer
}

Prevention

When it happens

Trigger: Calling AsyncObserver.SelectMany<TSource, TResult>(null, selector), or passing an observer variable that a factory/composition method returned as null.

Common situations: Building custom operator pipelines where the downstream observer comes from another operator's return value that silently returned null, misordered tuple construction of (observer, disposable) pairs, or typo'd variable assignment in observer-chain setup.

Related errors


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

Appendix: source

Thrown at AsyncRx.NET/System.Reactive.Async/Linq/Operators/SelectMany.cs:187

                source,
                (collectionSelector, resultSelector),
                static async (source, state, observer) =>
                {
                    var (sink, inner) = AsyncObserver.SelectMany(observer, state.collectionSelector, state.resultSelector);

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

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

    public partial class AsyncObserver
    {
        public static (IAsyncObserver<TSource>, IAsyncDisposable) SelectMany<TSource, TResult>(IAsyncObserver<TResult> observer, Func<TSource, IAsyncObservable<TResult>> selector)
        {
            if (observer == null)
                throw new ArgumentNullException(nameof(observer));
            if (selector == null)
                throw new ArgumentNullException(nameof(selector));

            return SelectMany<TSource, TResult, TResult>(observer, x => new ValueTask<IAsyncObservable<TResult>>(selector(x)), (x, y) => new ValueTask<TResult>(y));
        }

        public static (IAsyncObserver<TSource>, IAsyncDisposable) SelectMany<TSource, TResult>(IAsyncObserver<TResult> observer, Func<TSource, ValueTask<IAsyncObservable<TResult>>> selector)
        {
            if (observer == null)
                throw new ArgumentNullException(nameof(observer));
            if (selector == null)
                throw new ArgumentNullException(nameof(selector));

            return SelectMany<TSource, TResult, TResult>(observer, selector, (x, y) => new ValueTask<TResult>(y));
        }

        public static (IAsyncObserver<TSource>, IAsyncDisposable) SelectMany<TSource, TCollection, TResult>(IAsyncObserver<TResult> observer, Func<TSource, IAsyncObservable<TCollection>> collectionSelector, Func<TSource, TCollection, TResult> resultSelector)
        {

View on GitHub (pinned to 94b5d5ab91)