dotnet/reactive · error · ArgumentNullException

Value cannot be null. (Parameter 'collectionSelector')

Error message

Value cannot be null. (Parameter 'collectionSelector')

What it means

SelectMany (fully async overload) throws ArgumentNullException('collectionSelector') because the ValueTask-returning collectionSelector delegate was null. The library validates all arguments eagerly at the SelectMany call site, so this surfaces immediately rather than when the first element is processed. Supply a valid async collection selector to construct the operator.

Solutions

  1. Provide a non-null Func<TSource,int,ValueTask<IAsyncObservable<TCollection>>> collectionSelector
  2. If inner sequences are optional, pass an async lambda returning an empty observable
  3. Null-check the resolved delegate at composition time and fail with context

Example fix

// before
var result = source.SelectMany(_selectorResolver(), rs); // resolver returned null
// after
var cs = _selectorResolver() ?? (async (x, i) => ValueTask.FromResult(AsyncObservable.Empty<TCollection>()));
var result = source.SelectMany(cs, rs);
Defensive patterns

Strategy: validation

Validate before calling

if (source is null) throw new ArgumentNullException(nameof(source));
if (collectionSelector is null) throw new ArgumentNullException(nameof(collectionSelector));
if (resultSelector is null) throw new ArgumentNullException(nameof(resultSelector));

Type guard

static bool IsValidAsyncCollectionSelector<TSource,TCollection>(Func<TSource,int,ValueTask<IAsyncObservable<TCollection>>>? cs) => cs is not null;

Try / catch

try { var result = source.SelectMany(asyncCs, asyncRs); }
catch (ArgumentNullException ex) when (ex.ParamName == "collectionSelector")
{ /* resolve/supply the async collection selector */ }

Prevention

When it happens

Trigger: Calling SelectMany<TSource,TCollection,TResult>(source, collectionSelector, resultSelector) where collectionSelector == null; common when the inner-observable factory is resolved from DI/config and the resolution returned null.

Common situations: Configuration-driven pipelines where the selector is optional and unset; refactors that swapped Task-returning lambdas for ValueTask ones and dropped the argument; mocks returning null delegates.

Related errors


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

Appendix: source

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

            return CreateAsyncObservable<TResult>.From(
                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 static IAsyncObservable<TResult> SelectMany<TSource, TCollection, TResult>(this IAsyncObservable<TSource> source, Func<TSource, int, ValueTask<IAsyncObservable<TCollection>>> collectionSelector, Func<TSource, int, TCollection, int, ValueTask<TResult>> resultSelector)
        {
            if (source == null)
                throw new ArgumentNullException(nameof(source));
            if (collectionSelector == null)
                throw new ArgumentNullException(nameof(collectionSelector));
            if (resultSelector == null)
                throw new ArgumentNullException(nameof(resultSelector));

            return CreateAsyncObservable<TResult>.From(
                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

View on GitHub (pinned to 94b5d5ab91)