dotnet/reactive · error · ArgumentNullException

selector

Error message

selector

What it means

Then's selector must be a non-null Expression<Func<TSource, TResult>> — unlike the observable variant, this must be an expression tree so it can be embedded in the queryable expression. Passing null (or an ordinary delegate where an expression is required) triggers ArgumentNullException("selector") before the QueryablePlan is constructed.

Solutions

  1. Pass a concrete expression lambda, e.g. x => x.ToString().
  2. Provide a default projection expression when the configured one is null.
  3. Fix the expression-building code so it always compiles and assigns the selector.

Example fix

// before
Expression<Func<int, string>> proj = null;
var plan = source.Then(proj);
// after
Expression<Func<int, string>> proj = x => x.ToString();
var plan = source.Then(proj);
Defensive patterns

Strategy: validation

Validate before calling

if (selector is null) selector = x => default!; // or fail fast
var plan = source.Then(selector);

Type guard

bool HasProjection<TIn, TOut>(Expression<Func<TIn, TOut>>? e) => e is not null;

Try / catch

try { var plan = source.Then(proj); }
catch (ArgumentNullException ex) when (ex.ParamName == "selector") { var plan = source.Then(x => default(TResult)!); }

Prevention

When it happens

Trigger: Calling source.Then(null) or passing a lambda variable typed as Expression<Func<TSource, TResult>> that is null; also passing a non-expression Func where the compiler would force conversion that fails at runtime with a null expression instance.

Common situations: Dynamic query construction where the projection expression is conditionally built and ends up null, or reflection-based composition that fails to compile the expression.

Related errors


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

Appendix: source

Thrown at Rx.NET/Source/src/System.Reactive/Linq/Qbservable.Joins.cs:65

        /// <summary>
        /// Matches when the observable sequence has an available element and projects the element by invoking the selector function.
        /// </summary>
        /// <typeparam name="TSource">The type of the elements in the source sequence.</typeparam>
        /// <typeparam name="TResult">The type of the elements in the result sequence, returned by the selector function.</typeparam>
        /// <param name="source">Observable sequence to apply the selector on.</param>
        /// <param name="selector">Selector that will be invoked for elements in the source sequence.</param>
        /// <returns>Plan that produces the projected results, to be fed (with other plans) to the When operator.</returns>
        /// <exception cref="ArgumentNullException"><paramref name="source"/> or <paramref name="selector"/> is null.</exception>
        public static QueryablePlan<TResult> Then<TSource, TResult>(this IQbservable<TSource> source, Expression<Func<TSource, TResult>> selector)
        {
            if (source == null)
            {
                throw new ArgumentNullException(nameof(source));
            }

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

            return new QueryablePlan<TResult>(
                Expression.Call(
                    null,
                    new Func<IQbservable<TSource>, Expression<Func<TSource, TResult>>, QueryablePlan<TResult>>(Then).Method,
                    source.Expression,
                    selector
                )
            );
        }

        /// <summary>
        /// Joins together the results from several patterns.
        /// </summary>
        /// <typeparam name="TResult">The type of the elements in the result sequence, obtained from the specified patterns.</typeparam>
        /// <param name="provider">Query provider used to construct the <see cref="IQbservable{T}"/> data source.</param>
        /// <param name="plans">A series of plans created by use of the Then operator on patterns.</param>

View on GitHub (pinned to 94b5d5ab91)