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
- Pass a valid Expression<Func<TSource1,TSource2,TResult>> lambda to Then, e.g. (a, b) => new Result(a, b)
- Check the variable holding the selector for null before calling Then and fix the assignment path
- 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
- Always pass expression lambdas directly inline to Then rather than via nullable variables
- Enable nullable reference types so null selector variables are flagged at compile time
- Never cast or convert Func delegates to Expression dynamically without a null check
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
- Value cannot be null. (Parameter 'onCompleted')
- Value cannot be null. (Parameter 'onNext')
- Value cannot be null. (Parameter 'onError')
- Value cannot be null. (Parameter 'conversion')
- Value cannot be null. (Parameter 'source8')
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)