dotnet/reactive · error · ArgumentNullException
Value cannot be null. (Parameter 'observer')
Error message
Value cannot be null. (Parameter 'observer')
What it means
AsyncObserver.GroupBy is the internal factory that builds the observer tuple driving the GroupBy pipeline. It validates observer first and throws ArgumentNullException when it is null. This overload is normally invoked by the public GroupBy operator and by GroupByCore, so hitting it usually means an observer pipeline was assembled manually with a missing observer.
Solutions
- Pass the real IAsyncObserver instance obtained from CreateAsyncObservable.From's callback; do not construct the observer pipeline with null.
- If building a custom operator, ensure your observerFactory returns a valid observer before calling AsyncObserver.GroupBy.
- Guard with a null check on the observer before invoking the factory.
Example fix
// before return AsyncObserver.GroupBy(null, subscription, keySelector); // after if (observer == null) throw new ArgumentNullException(nameof(observer)); return AsyncObserver.GroupBy(observer, subscription, keySelector);
Defensive patterns
Strategy: validation
Validate before calling
if (observer == null) throw new ArgumentNullException(nameof(observer)); var (o, d) = AsyncObserver.GroupBy(observer, subscription, keySelector);
Type guard
bool CanBuildGroupBy<TSource, TKey>(IAsyncObserver<IGroupedAsyncObservable<TKey, TSource>>? observer) => observer is not null;
Try / catch
try
{
var (o, d) = AsyncObserver.GroupBy(observer, subscription, keySelector);
}
catch (ArgumentNullException ex) when (ex.ParamName == "observer")
{
throw new InvalidOperationException("GroupBy requires a non-null observer from the operator callback.", ex);
} Prevention
- Only call AsyncObserver.* factories from inside CreateAsyncObservable.From callbacks where the observer is guaranteed.
- Use static lambdas with state tuples as the library does to avoid capturing nulls.
- Unit-test custom operators with a recording IAsyncObserver stub.
When it happens
Trigger: Calling AsyncObserver.GroupBy<TSource, TKey>(observer, subscription, keySelector) directly (or via a custom operator builder) with a null IAsyncObserver<IGroupedAsyncObservable<TKey, TSource>>.
Common situations: Hand-rolling custom async operators on top of AsyncObserver.*; a CreateAsyncObservable callback receiving and forwarding a null observer; wiring the observer tuple in the wrong order so null lands in the observer slot.
Related errors
- Value cannot be null. (Parameter 'observer')
- Value cannot be null. (Parameter 'observer')
- Value cannot be null. (Parameter 'subscription')
- Value cannot be null. (Parameter 'observer')
- Value cannot be null. (Parameter 'observer')
AI-assisted analysis of dotnet/reactive@94b5d5ab91 (2026-09-15).
Data as JSON: /api/errors/fd360b1e88812ca3.
Report an issue: GitHub.
Appendix: source
Thrown at AsyncRx.NET/System.Reactive.Async/Linq/Operators/GroupBy.cs:288
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);
await d.AssignAsync(inner).ConfigureAwait(false);
return subscription;
}
}
public partial class AsyncObserver
{
public static (IAsyncObserver<TSource>, IAsyncDisposable) GroupBy<TSource, TKey>(IAsyncObserver<IGroupedAsyncObservable<TKey, TSource>> observer, IAsyncDisposable subscription, Func<TSource, 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, 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)