dotnet/reactive · error · ArgumentNullException

ArgumentNullException: selector

Error message

ArgumentNullException: selector

What it means

This SelectMany overload (selector returning IAsyncOperation<TResult>) throws ArgumentNullException when the selector delegate is null. The selector is invoked per element to produce the WinRT async operation, so a null delegate makes the composition impossible. Validation is eager, before any subscription.

Solutions

  1. Supply a non-null selector lambda, e.g. x => x.CreateAsyncOperation().
  2. Null-check injected/configured selectors before building the query.
  3. Ensure DI registrations or factory methods actually provide the selector delegate.

Example fix

// before
Func<Item, IAsyncOperation<Result>> sel = _config.Selector; // may be null
var q = source.SelectMany(sel);
// after
var selector = _config.Selector ?? throw new InvalidOperationException("Selector not configured");
var q = source.SelectMany(x => selector(x));
Defensive patterns

Strategy: validation

Validate before calling

if (selector is null) throw new InvalidOperationException("selector delegate must be configured before SelectMany");

Type guard

static bool HasSelector<T, R>(Func<T, IAsyncOperation<R>>? f) => f is not null;

Try / catch

try { var q = source.SelectMany(selector); }
catch (ArgumentNullException ex) when (ex.ParamName == "selector") { /* fail with clear configuration error */ }

Prevention

When it happens

Trigger: Calling source.SelectMany<TSource, TResult>(selector) where the Func<TSource, IAsyncOperation<TResult>> argument is null.

Common situations: A selector stored in a field, injected dependency, or dictionary that was never initialized; passing a null method group from optional configuration; refactoring removed the lambda but left the call.

Related errors


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

Appendix: source

Thrown at Rx.NET/Source/src/System.Reactive.WindowsRuntime/System.Reactive.Linq/WindowsObservable.StandardSequenceOperators.cs:35

        /// Projects each element of an observable sequence to a Windows Runtime asynchronous operation and merges all of the asynchronous operation results into one observable sequence.
        /// </summary>
        /// <typeparam name="TSource">The type of the elements in the source sequence.</typeparam>
        /// <typeparam name="TResult">The type of the result produced by the projected asynchronous operations and the elements in the merged result sequence.</typeparam>
        /// <param name="source">An observable sequence of elements to project.</param>
        /// <param name="selector">A transform function to apply to each element.</param>
        /// <returns>An observable sequence whose elements are the result of the asynchronous operations executed for each element of the input sequence.</returns>
        /// <exception cref="ArgumentNullException"><paramref name="source"/> or <paramref name="selector"/> is null.</exception>
        /// <remarks>This overload supports composition of observable sequences and Windows Runtime asynchronous operations, without requiring manual conversion of the asynchronous operations to observable sequences using <see cref="AsyncInfoObservableExtensions.ToObservable{TResult}(IAsyncOperation{TResult})"/>.</remarks>
        public static IObservable<TResult> SelectMany<TSource, TResult>(this IObservable<TSource> source, Func<TSource, IAsyncOperation<TResult>> selector)
        {
            if (source == null)
            {
                throw new ArgumentNullException(nameof(source));
            }

            if (selector == null)
            {
                throw new ArgumentNullException(nameof(selector));
            }

            return source.SelectMany(x => selector(x).ToObservable());
        }

        /// <summary>
        /// Projects each element of an observable sequence to a Windows Runtime asynchronous operation and merges all of the asynchronous operation results into one observable sequence.
        /// </summary>
        /// <typeparam name="TSource">The type of the elements in the source sequence.</typeparam>
        /// <typeparam name="TResult">The type of the result produced by the projected asynchronous operations and the elements in the merged result sequence.</typeparam>
        /// <typeparam name="TProgress">The type of the reported progress objects, which get ignored by this query operator.</typeparam>
        /// <param name="source">An observable sequence of elements to project.</param>
        /// <param name="selector">A transform function to apply to each element.</param>
        /// <returns>An observable sequence whose elements are the result of the asynchronous operations executed for each element of the input sequence.</returns>
        /// <exception cref="ArgumentNullException"><paramref name="source"/> or <paramref name="selector"/> is null.</exception>
        /// <remarks>This overload supports composition of observable sequences and Windows Runtime asynchronous operations, without requiring manual conversion of the asynchronous operations to observable sequences using <see cref="AsyncInfoObservableExtensions.ToObservable{TResult}(IAsyncOperation{TResult})"/>.</remarks>
        public static IObservable<TResult> SelectMany<TSource, TResult, TProgress>(this IObservable<TSource> source, Func<TSource, IAsyncOperationWithProgress<TResult, TProgress>> selector)
        {

View on GitHub (pinned to 94b5d5ab91)