dotnet/reactive · error · ArgumentNullException

source

Error message

source

What it means

This SelectMany overload projects each element into a WinRT IAsyncOperation and throws ArgumentNullException when the source observable is null (the selector null check follows). Rx validates arguments eagerly before composing the async-operation sequence.

Solutions

  1. Ensure the source observable is non-null before calling SelectMany
  2. Also verify the selector itself is non-null (next guard)
  3. Wrap optional sources: source ?? Observable.Empty<TSource>()
  4. Ensure async factories throw on failure rather than returning null observables

Example fix

// before
IObservable<StorageFile> files = null;
files.SelectMany(f => f.OpenAsync()).Subscribe(...);
// after
IObservable<StorageFile> files = GetFiles() ?? Observable.Empty<StorageFile>();
files.SelectMany(f => f.OpenAsync()).Subscribe(...);
Defensive patterns

Strategy: validation

Validate before calling

if (source == null) throw new ArgumentNullException(nameof(source));
if (selector == null) throw new ArgumentNullException(nameof(selector));

Type guard

static IObservable<TResult> SafeSelectMany<T, TResult>(IObservable<T> source, Func<T, Windows.Foundation.IAsyncOperation<TResult>> selector) => source?.SelectMany(selector) ?? Observable.Empty<TResult>();

Try / catch

try { obs.SelectMany(x => x.DoAsync()).Subscribe(...); }
catch (ArgumentNullException ex) { Log($"{ex.ParamName} null in SelectMany"); }

Prevention

When it happens

Trigger: Calling source.SelectMany(x => x.DoAsync()) where source is a null IObservable<TSource>, or where an upstream factory returned null; the selector returning null is a separate failure at runtime.

Common situations: Chaining SelectMany after a null-conditional expression on an optional service; passing the result of an async factory that returned null instead of throwing; WinRT async interop where the source was conditionally created.

Related errors


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

Appendix: source

Thrown at Rx.NET/Source/src/System.Reactive/Platforms/WinRT/Linq/WindowsObservable.StandardSequenceOperators.cs:27

namespace System.Reactive.Linq
{
    public static partial class WindowsObservable
    {
        /// <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>
        /// <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>

View on GitHub (pinned to 94b5d5ab91)