dotnet/reactive · error · ArgumentNullException
Value cannot be null. (Parameter 'elementSelector')
Error message
Value cannot be null. (Parameter 'elementSelector')
What it means
AsyncRx.NET's GroupBy operator validates its arguments eagerly and throws ArgumentNullException when elementSelector is null. The elementSelector lambda maps each source element to the element exposed on each IGroupedAsyncObservable, so the library refuses to build the grouping pipeline without it. This is a fail-fast guard, not a runtime aggregation failure.
Solutions
- Pass a non-null element selector lambda, e.g. x => x, when the element is the source item itself.
- Check which GroupBy overload you intend; if no projection is needed use the overload without elementSelector instead of passing null.
- Add a null check or require!-style guard on the selector before calling GroupBy.
Example fix
// before var grouped = source.GroupBy(x => x.Key, (Func<Item, Item>)null); // after var grouped = source.GroupBy(x => x.Key, x => x);
Defensive patterns
Strategy: validation
Validate before calling
if (source == null) throw new ArgumentNullException(nameof(source)); if (keySelector == null) throw new ArgumentNullException(nameof(keySelector)); if (elementSelector == null) throw new ArgumentNullException(nameof(elementSelector)); var grouped = source.GroupBy(keySelector, elementSelector);
Type guard
bool IsValid<T, TKey, TElem>(Func<T, TKey> k, Func<T, TElem> e) => k != null && e != null;
Try / catch
try
{
var grouped = source.GroupBy(keySelector, elementSelector);
}
catch (ArgumentNullException ex) when (ex.ParamName == "elementSelector")
{
grouped = source.GroupBy(keySelector, x => x); // identity projection fallback
} Prevention
- Use the overload without elementSelector when no projection is needed instead of passing null.
- Keep selectors as non-nullable Func<,> fields initialized at construction.
- Enable C# nullable reference types so nullable delegates are flagged at compile time.
When it happens
Trigger: Calling any GroupBy overload that accepts an elementSelector (e.g. AsyncObservable.GroupBy(source, keySelector, elementSelector), with capacity, or with comparer) and passing null for elementSelector.
Common situations: Developers call a GroupBy overload they believe takes only a keySelector but accidentally supply an extra null argument; conditional lambda construction returns null; refactoring moves the element projection out and passes a nullable delegate field that was never assigned.
Related errors
- Value cannot be null. (Parameter 'comparer')
- ArgumentNullException: elementSelector
- 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/9ef7ae506d86426a.
Report an issue: GitHub.
Appendix: source
Thrown at AsyncRx.NET/System.Reactive.Async/Linq/Operators/GroupBy.cs:258
if (elementSelector == null)
throw new ArgumentNullException(nameof(elementSelector));
if (capacity < 0)
throw new ArgumentOutOfRangeException(nameof(capacity));
return CreateAsyncObservable<IGroupedAsyncObservable<TKey, TElement>>.From(
source,
(keySelector, elementSelector, capacity),
static (source, state, observer) => GroupByCore(source, observer, (o, d) => AsyncObserver.GroupBy(o, d, state.keySelector, state.elementSelector, state.capacity)));
}
public static IAsyncObservable<IGroupedAsyncObservable<TKey, TElement>> GroupBy<TSource, TKey, TElement>(this IAsyncObservable<TSource> source, Func<TSource, ValueTask<TKey>> keySelector, Func<TSource, ValueTask<TElement>> elementSelector, int capacity, IEqualityComparer<TKey> comparer)
{
if (source == null)
throw new ArgumentNullException(nameof(source));
if (keySelector == null)
throw new ArgumentNullException(nameof(keySelector));
if (elementSelector == null)
throw new ArgumentNullException(nameof(elementSelector));
if (capacity < 0)
throw new ArgumentOutOfRangeException(nameof(capacity));
if (comparer == null)
throw new ArgumentNullException(nameof(comparer));
return CreateAsyncObservable< IGroupedAsyncObservable<TKey, TElement>>.From(
source,
(keySelector, elementSelector, capacity, comparer),
static (source, state, observer) => GroupByCore(source, observer, (o, d) => AsyncObserver.GroupBy(o, d, state.keySelector, state.elementSelector, state.capacity, state.comparer)));
}
private static async ValueTask<IAsyncDisposable> GroupByCore<TSource, TKey, TElement>(IAsyncObservable<TSource> source, IAsyncObserver<IGroupedAsyncObservable<TKey, TElement>> observer, Func<IAsyncObserver<IGroupedAsyncObservable<TKey, TElement>>, IAsyncDisposable, (IAsyncObserver<TSource>, IAsyncDisposable)> createObserver)
{
var d = new SingleAssignmentAsyncDisposable();
var (sink, subscription) = createObserver(observer, d);
var inner = await source.SubscribeSafeAsync(sink).ConfigureAwait(false);View on GitHub (pinned to 94b5d5ab91)