dotnet/reactive · error · ArgumentNullException
Value cannot be null. (Parameter 'taskSelector')
Error message
Value cannot be null. (Parameter 'taskSelector')
What it means
The task-based SelectMany overload requires a non-null taskSelector delegate that maps each source element to a Task<TTaskResult>. A null taskSelector would make it impossible to produce the inner sequences, so the operator throws ArgumentNullException synchronously before returning an observable. Rx throws these argument-null exceptions eagerly at call time rather than delivering them through the stream.
Solutions
- Pass a non-null lambda or method group as the taskSelector argument
- Check any Func field/property feeding the call and initialize it before use
- If the selector is optional, branch: use a different overload or Observable.Empty when no selector is available
- Wrap the operator call in a guard that throws a descriptive exception naming the missing selector
Example fix
// before
Func<int, Task<string>>? loader = _config.EnableFetch ? FetchAsync : null;
var result = source.SelectMany(loader, (x, r) => r); // throws when null
// after
var result = _config.EnableFetch
? source.SelectMany(FetchAsync, (x, r) => r)
: Observable.Empty<string>(); Defensive patterns
Strategy: validation
Validate before calling
if (taskSelector is null) throw new ArgumentNullException(nameof(taskSelector));
Type guard
static bool HasSelector<TSource, TRes>(Func<TSource, Task<TRes>>? selector) => selector is not null;
Try / catch
try { var result = source.SelectMany(taskSelector, resultSelector); }
catch (ArgumentNullException ex) when (ex.ParamName == "taskSelector") { /* supply a default selector or skip the operation */ } Prevention
- Prefer method groups over nullable delegate fields
- Resolve delegates at startup/configuration time, not per-call
- Enable nullable reference types so Func fields declared nullable surface the risk
When it happens
Trigger: Calling Observable.SelectMany(source, taskSelector, resultSelector) where taskSelector is null - typically a null lambda variable, an uninitialized Func field, or a conditional expression that resolved to null.
Common situations: Storing selector delegates in nullable fields or configuration-driven lookups that fail to resolve; passing the result of a method that returns Func<TSource, Task<T>>? when the mapping is not registered; copy-paste refactors that removed the lambda body.
Related errors
- action (Parameter 'action')
- action
- Value cannot be null. (Parameter 'selector')
- Value cannot be null. (Parameter 'newCollector')
- Value cannot be null. (Parameter 'merge')
AI-assisted analysis of dotnet/reactive@94b5d5ab91 (2026-09-15).
Data as JSON: /api/errors/d46def4fb878cd8c.
Report an issue: GitHub.
Appendix: source
Thrown at Rx.NET/Source/src/System.Reactive/Linq/Observable.StandardSequenceOperators.cs:1253
/// <typeparam name="TSource">The type of the elements in the source sequence.</typeparam>
/// <typeparam name="TTaskResult">The type of the results produced by the projected intermediate tasks.</typeparam>
/// <typeparam name="TResult">The type of the elements in the result sequence, obtained by using the selector to combine source sequence elements with their corresponding intermediate task results.</typeparam>
/// <param name="source">An observable sequence of elements to project.</param>
/// <param name="taskSelector">A transform function to apply to each element.</param>
/// <param name="resultSelector">A transform function to apply to each element of the intermediate sequence.</param>
/// <returns>An observable sequence whose elements are the result of obtaining a task for each element of the input sequence and then mapping the task's result and its corresponding source element to a result element.</returns>
/// <exception cref="ArgumentNullException"><paramref name="source"/> or <paramref name="taskSelector"/> or <paramref name="resultSelector"/> is null.</exception>
/// <remarks>This overload supports using LINQ query comprehension syntax in C# and Visual Basic to compose observable sequences and tasks, without requiring manual conversion of the tasks to observable sequences using <see cref="TaskObservableExtensions.ToObservable{TResult}(Task{TResult})"/>.</remarks>
public static IObservable<TResult> SelectMany<TSource, TTaskResult, TResult>(this IObservable<TSource> source, Func<TSource, Task<TTaskResult>> taskSelector, Func<TSource, TTaskResult, TResult> resultSelector)
{
if (source == null)
{
throw new ArgumentNullException(nameof(source));
}
if (taskSelector == null)
{
throw new ArgumentNullException(nameof(taskSelector));
}
if (resultSelector == null)
{
throw new ArgumentNullException(nameof(resultSelector));
}
return s_impl.SelectMany(source, taskSelector, resultSelector);
}
/// <summary>
/// Projects each element of an observable sequence to a task by incorporating the element's index, invokes the result selector for the source element and the task result, and merges the results into one observable sequence.
/// </summary>
/// <typeparam name="TSource">The type of the elements in the source sequence.</typeparam>
/// <typeparam name="TTaskResult">The type of the results produced by the projected intermediate tasks.</typeparam>
/// <typeparam name="TResult">The type of the elements in the result sequence, obtained by using the selector to combine source sequence elements with their corresponding intermediate task results.</typeparam>
/// <param name="source">An observable sequence of elements to project.</param>
/// <param name="taskSelector">A transform function to apply to each element; the second parameter of the function represents the index of the source element.</param>View on GitHub (pinned to 94b5d5ab91)