dotnet/reactive · error · ArgumentNullException

throw new ArgumentNullException(nameof(source))

Error message

throw new ArgumentNullException(nameof(source))

What it means

QbservableEx.Expand(source, selector) recursively re-expands elements via selector and needs a valid IQbservable source to build the query. A null source throws ArgumentNullException named 'source' immediately at composition time. This is eager validation so bad queries fail at the call site, not on a remote provider.

Solutions

  1. Pass a non-null IQbservable<TSource>; fall back to Observable.Empty<TSource>() when there is no data
  2. Fix the upstream factory/method that returned a null source
  3. Add a null check with a clear domain message before calling Expand

Example fix

// before
source.Expand(x => Observable.Return(x)); // source is null
// after
var src = source ?? Observable.Empty<TSource>();
src.Expand(x => Observable.Return(x));
Defensive patterns

Strategy: validation

Validate before calling

if (source == null)
    throw new InvalidOperationException("Expand requires a non-null source; use Observable.Empty<TSource>()");

Type guard

bool HasSource<T>(IQbservable<T> s) => s is not null;

Try / catch

try
{
    var query = source.Expand(x => Observable.Return(x));
}
catch (ArgumentNullException ex) when (ex.ParamName == "source")
{
    logger.LogError(ex, "Expand source was null");
}

Prevention

When it happens

Trigger: Calling Qbservable.Expand(null, selector) — commonly when the source query was the result of a null-returning factory, a failed FirstOrDefault-style lookup, or an uninitialized member.

Common situations: Chaining Expand after a conditional pipeline where an earlier operator returned null; dictionary/config-driven query construction with a missing key; test doubles returning null instead of an empty qbservable.

Related errors


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

Appendix: source

Thrown at Rx.NET/Source/src/System.Reactive/Linq/QbservableEx.Homoicon.cs:1023

            );
        }
#endif

#if !STABLE
        /// <summary>
        /// Expands an observable sequence by recursively invoking selector.
        /// </summary>
        /// <typeparam name="TSource">The type of the elements in the source sequence and each of the recursively expanded sources obtained by running the selector function.</typeparam>
        /// <param name="source">Source sequence with the initial elements.</param>
        /// <param name="selector">Selector function to invoke for each produced element, resulting in another sequence to which the selector will be invoked recursively again.</param>
        /// <returns>An observable sequence containing all the elements produced by the recursive expansion.</returns>
        /// <exception cref="ArgumentNullException">
        /// <paramref name="source" /> or <paramref name="selector" /> is null.</exception>
        [Experimental]
        public static IQbservable<TSource> Expand<TSource>(this IQbservable<TSource> source, Expression<Func<TSource, IObservable<TSource>>> selector)
        {
            if (source == null)
                throw new ArgumentNullException(nameof(source));
            if (selector == null)
                throw new ArgumentNullException(nameof(selector));

            return source.Provider.CreateQuery<TSource>(
                Expression.Call(
                    null,
                    new Func<IQbservable<TSource>, Expression<Func<TSource, IObservable<TSource>>>, IQbservable<TSource>>(Expand<TSource>).Method,
                    source.Expression,
                    selector
                )
            );
        }
#endif

#if !STABLE
        /// <summary>
        /// Expands an observable sequence by recursively invoking selector, using the specified scheduler to enumerate the queue of obtained sequences.
        /// </summary>

View on GitHub (pinned to 94b5d5ab91)