dotnet/reactive · error · ArgumentNullException

Value cannot be null. (Parameter 'selector')

Error message

Value cannot be null. (Parameter 'selector')

What it means

This ArgumentNullException is thrown by QueryablePattern<TSource1,TSource2>.Then<TResult> when the selector expression is null. The Rx Queryable pattern builds an expression tree describing the join, so a non-null selector expression is mandatory; the guard at the top of the method fails fast instead of failing later inside Expression.Call.

Solutions

  1. Pass a valid Expression<Func<TSource1,TSource2,TResult>> lambda to Then, e.g. (a, b) => new Result(a, b)
  2. Check the variable holding the selector for null before calling Then and fix the assignment path
  3. If the selector is optional, return early or use a default projection instead of passing null

Example fix

// before
Expression<Func<int, string, Result>> sel = GetSelector(); // returns null
var plan = pattern.Then(sel);
// after
var sel = GetSelector() ?? ((int a, string b) => new Result(a, b));
var plan = pattern.Then(sel);
Defensive patterns

Strategy: validation

Validate before calling

if (selector is null) throw new ArgumentException("selector must be a non-null expression", nameof(selector));

Type guard

static bool IsValidSelector<TSource1,TSource2,TResult>(Expression<Func<TSource1,TSource2,TResult>>? s) => s is not null;

Try / catch

try { var plan = pattern.Then(selector); }
catch (ArgumentNullException ex) when (ex.ParamName == "selector") { /* log and supply default projection */ }

Prevention

When it happens

Trigger: Calling Then<TSource1,TSource2,TResult>((Expression<Func<TSource1,TSource2,TResult>>)null) — e.g. passing a null result of a factory, a variable that was never assigned, or a conditional expression that evaluated to null.

Common situations: Building IQbservable join queries where the selector comes from configuration, reflection, or an optional delegate parameter; refactoring that removed a lambda but left the Then call; type mismatches forcing a cast of null.

Related errors


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

Appendix: source

Thrown at Rx.NET/Source/src/System.Reactive/Joins/QueryablePattern.Generated.cs:65

                    Expression,
                    m,
                    Qbservable.GetSourceExpression(other)
                )
            );
        }

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

            var t = typeof(QueryablePattern<TSource1, TSource2>);
            var m = t.GetMethod(nameof(Then)).MakeGenericMethod(typeof(TResult));
            return new QueryablePlan<TResult>(
                Expression.Call(
                    Expression,
                    m,
                    selector
                )
            );
        }
    }

    /// <summary>
    /// Represents a join pattern over three observable sequences.
    /// </summary>
    /// <typeparam name="TSource1">The type of the elements in the first source sequence.</typeparam>

View on GitHub (pinned to 94b5d5ab91)