dotnet/reactive · error · ArgumentNullException
Value cannot be null. (Parameter 'resultSelector')
Error message
Value cannot be null. (Parameter 'resultSelector')
What it means
The async SelectMany operator on IAsyncObservable<TSource> throws ArgumentNullException because its resultSelector parameter was null. This operator requires a function that combines each source element with each inner-collection element to produce the final result; without it the operator cannot be constructed. The library validates all delegate arguments eagerly at operator-creation time rather than failing later during subscription.
Solutions
- Pass a non-null resultSelector lambda, e.g. (x, y) => Combine(x, y).
- If the result is just the inner element, use the two-argument overload SelectMany(source, collectionSelector) instead of passing a null selector.
- Check where the delegate comes from (config, dictionary lookup, optional parameter default) and default it to a valid function instead of null.
- Guard the call site: if (resultSelector == null) throw/log before invoking SelectMany so the failure points at your code.
Example fix
// before var qs = AsyncObservable.SelectMany(source, x => GetInner(x), null); // after var qs = AsyncObservable.SelectMany(source, x => GetInner(x), (src, inner) => new Result(src.Id, inner));
Defensive patterns
Strategy: validation
Validate before calling
if (source is null) throw new ArgumentNullException(nameof(source)); if (collectionSelector is null) throw new ArgumentNullException(nameof(collectionSelector)); if (resultSelector is null) throw new ArgumentNullException(nameof(resultSelector));
Type guard
static bool IsValidSelectManyArgs<TSource, TCollection, TResult>(
IAsyncObservable<TSource> source,
Func<TSource, IAsyncObservable<TCollection>> collectionSelector,
Func<TSource, TCollection, TResult> resultSelector)
=> source is not null && collectionSelector is not null && resultSelector is not null; Try / catch
try
{
var qs = AsyncObservable.SelectMany(source, collectionSelector, resultSelector);
}
catch (ArgumentNullException ex) when (ex.ParamName == "resultSelector")
{
// provide default projection or surface config error
resultSelector = (src, inner) => default;
} Prevention
- Never pass nullable delegate parameters straight into operator calls; default them at the boundary.
- Prefer method groups over variables so the compiler enforces non-null references.
- When a delegate comes from configuration or a registry, validate it right after resolution.
When it happens
Trigger: Calling AsyncObservable.SelectMany(source, collectionSelector, resultSelector) with a null third argument, e.g. SelectMany(source, x => inner, (Func<TSource,TCollection,TResult>)null), or passing a resultSelector variable that was never assigned.
Common situations: Conditional delegate assignment (resultSelector only assigned in one branch), passing the output of a factory/lookup method that returned null, refactoring from a two-argument SelectMany overload to the three-argument one and forgetting the extra argument, or dynamic composition where a selector map has no entry.
Related errors
- Value cannot be null. (Parameter 'observer')
- Value cannot be null. (Parameter 'selector')
- Value cannot be null. (Parameter 'scheduler')
- Value cannot be null. (Parameter 'source')
- Value cannot be null.
AI-assisted analysis of dotnet/reactive@94b5d5ab91 (2026-09-15).
Data as JSON: /api/errors/0c6879b310a64484.
Report an issue: GitHub.
Appendix: source
Thrown at AsyncRx.NET/System.Reactive.Async/Linq/Operators/SelectMany.cs:166
(collectionSelector, resultSelector),
static async (source, state, observer) =>
{
var (sink, inner) = AsyncObserver.SelectMany(observer, state.collectionSelector, state.resultSelector);
var subscription = await source.SubscribeSafeAsync(sink).ConfigureAwait(false);
return StableCompositeAsyncDisposable.Create(subscription, inner);
});
}
public static IAsyncObservable<TResult> SelectMany<TSource, TCollection, TResult>(this IAsyncObservable<TSource> source, Func<TSource, int, ValueTask<IAsyncObservable<TCollection>>> collectionSelector, Func<TSource, int, TCollection, int, ValueTask<TResult>> resultSelector)
{
if (source == null)
throw new ArgumentNullException(nameof(source));
if (collectionSelector == null)
throw new ArgumentNullException(nameof(collectionSelector));
if (resultSelector == null)
throw new ArgumentNullException(nameof(resultSelector));
return CreateAsyncObservable<TResult>.From(
source,
(collectionSelector, resultSelector),
static async (source, state, observer) =>
{
var (sink, inner) = AsyncObserver.SelectMany(observer, state.collectionSelector, state.resultSelector);
var subscription = await source.SubscribeSafeAsync(sink).ConfigureAwait(false);
return StableCompositeAsyncDisposable.Create(subscription, inner);
});
}
}
public partial class AsyncObserver
{
public static (IAsyncObserver<TSource>, IAsyncDisposable) SelectMany<TSource, TResult>(IAsyncObserver<TResult> observer, Func<TSource, IAsyncObservable<TResult>> selector)View on GitHub (pinned to 94b5d5ab91)