dotnet/reactive · error · ArgumentNullException
observer
Error message
observer
What it means
GroupBy throws ArgumentNullException because the required observer (downstream IAsyncObserver<IGroupedAsyncObservable<TKey,TSource>>) is null. The operator validates its core arguments eagerly so an invalid subscription fails immediately rather than when events flow. It is part of the standard null-guard pattern in AsyncRx.NET operator entry points.
Solutions
- Ensure the IAsyncObserver<IGroupedAsyncObservable<TKey,TSource>> passed to GroupBy is non-null; construct it with a factory such as AsyncObserver.Create<TSource>(...).
- Check the argument order: the observer is the first parameter, the subscription the second — swapped arguments commonly make the observer null.
- Verify any variable holding the observer is initialized before GroupBy is invoked (defer construction until both observer and subscription exist).
- If the observer comes from another operator, confirm that operator's return value is not null on the code path taken.
Example fix
// before var grp = GroupBy<TSource, TKey>(observer, subscription, x => x.Key); // observer is null // after var obs = AsyncObserver.Create<TSource>(onNextAsync: x => default(ValueTask)); var grp = GroupBy<TSource, TKey>(obs, subscription, x => x.Key);
Defensive patterns
Strategy: validation
Validate before calling
if (observer == null) throw new InvalidOperationException("observer must be provided before GroupBy");
var grp = GroupBy<TSource, TKey>(observer, subscription, keySelector); Type guard
bool IsValidGroupByArgs<TSource, TKey>(IAsyncObserver<IGroupedAsyncObservable<TKey, TSource>> o) => o is not null;
Try / catch
try { var grp = GroupBy<TSource, TKey>(observer, subscription, keySelector); }
catch (ArgumentNullException ex) when (ex.ParamName == "observer") { /* fix pipeline wiring / log */ } Prevention
- Always construct the observer (e.g. via AsyncObserver.Create) immediately before calling GroupBy.
- Keep the (observer, subscription) parameter order in mind when upgrading between overloads.
- Enable nullable reference types (<Nullable>enable</Nullable>) so null observer variables are flagged at compile time.
When it happens
Trigger: Calling the 2-type-parameter GroupBy<TSource,TKey>(observer, subscription, keySelector) overload with a null observer, i.e. AsyncRx.NET.Linq.Operators.GroupBy(null, subscription, keySelector) or wiring a subscription whose observer was never created.
Common situations: Manually building operator chains where the observer is produced by a factory that returned null; passing a field that is not yet initialized because the observable pipeline was constructed before its observer; refactorings that swap the observer/subscription argument order.
Related errors
AI-assisted analysis of dotnet/reactive@94b5d5ab91 (2026-09-15).
Data as JSON: /api/errors/bdedc4d43f3cf76f.
Report an issue: GitHub.
Appendix: source
Thrown at AsyncRx.NET/System.Reactive.Async/Linq/Operators/GroupBy.cs:408
throw new ArgumentNullException(nameof(observer));
if (subscription == null)
throw new ArgumentNullException(nameof(subscription));
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 GroupBy<TSource, TKey, TElement>(observer, subscription, x => new ValueTask<TKey>(keySelector(x)), x => new ValueTask<TElement>(elementSelector(x)), capacity, comparer);
}
public static (IAsyncObserver<TSource>, IAsyncDisposable) GroupBy<TSource, TKey>(IAsyncObserver<IGroupedAsyncObservable<TKey, TSource>> observer, IAsyncDisposable subscription, Func<TSource, ValueTask<TKey>> keySelector)
{
if (observer == null)
throw new ArgumentNullException(nameof(observer));
if (subscription == null)
throw new ArgumentNullException(nameof(subscription));
if (keySelector == null)
throw new ArgumentNullException(nameof(keySelector));
return GroupBy(observer, subscription, keySelector, int.MaxValue, EqualityComparer<TKey>.Default);
}
public static (IAsyncObserver<TSource>, IAsyncDisposable) GroupBy<TSource, TKey>(IAsyncObserver<IGroupedAsyncObservable<TKey, TSource>> observer, IAsyncDisposable subscription, Func<TSource, ValueTask<TKey>> keySelector, IEqualityComparer<TKey> comparer)
{
if (observer == null)
throw new ArgumentNullException(nameof(observer));
if (subscription == null)
throw new ArgumentNullException(nameof(subscription));
if (keySelector == null)
throw new ArgumentNullException(nameof(keySelector));
if (comparer == null)
throw new ArgumentNullException(nameof(comparer));View on GitHub (pinned to 94b5d5ab91)