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
- Pass a concrete expression lambda, e.g. x => x.ToString().
- Provide a default projection expression when the configured one is null.
- 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
- Pass expression lambdas directly at the call site
- When building expressions dynamically, assert the compiled result is non-null
- Remember the qbservable overload needs Expression<>, not a plain Func
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)