dotnet/reactive · error · ArgumentNullException

ArgumentNullException: comparer

Error message

ArgumentNullException: comparer

What it means

GroupBy(source, keySelector, capacity, comparer) throws ArgumentNullException when comparer is null. A non-null IEqualityComparer<TKey> is mandatory in this overload; there is no implicit default-comparer fallback. Validation happens last in the argument-check sequence but still before any asynchronous work.

Solutions

  1. Pass a non-null comparer; use EqualityComparer<TKey>.Default for default semantics.
  2. Fix the comparer factory/DI registration so it returns an instance.
  3. Coalesce with comparer ?? EqualityComparer<TKey>.Default at the call site.

Example fix

// before
var groups = source.GroupBy(x => x.Key, 16, container.GetService<IEqualityComparer<Key>>()); // may be null
// after
var groups = source.GroupBy(x => x.Key, 16, container.GetService<IEqualityComparer<Key>>() ?? EqualityComparer<Key>.Default);
Defensive patterns

Strategy: validation

Validate before calling

if (comparer is null) comparer = EqualityComparer<TKey>.Default;

Type guard

static bool HasComparer<TKey>(IEqualityComparer<TKey> c) => c is not null;

Try / catch

try { var groups = source.GroupBy(keySelector, capacity, comparer); }
catch (ArgumentNullException ex) when (ex.ParamName == "comparer") { log.LogError(ex, "GroupBy comparer was null"); throw; }

Prevention

When it happens

Trigger: Calling GroupBy(source, keySelector, capacity, null) — comparer from DI/config resolution returning null, or a variable that was conditionally assigned.

Common situations: Missing DI registration for a custom comparer; comparer lookup by type name failing; conditional comparer selection with a branch that leaves it null.

Related errors


AI-assisted analysis of dotnet/reactive@94b5d5ab91 (2026-09-15). Data as JSON: /api/errors/7dd6c1a818a141ff. Report an issue: GitHub.

Appendix: source

Thrown at AsyncRx.NET/System.Reactive.Async/Linq/Operators/GroupBy.cs:66

            if (capacity < 0)
                throw new ArgumentOutOfRangeException(nameof(capacity));

            return CreateAsyncObservable<IGroupedAsyncObservable<TKey, TSource>>.From(
                source,
                (keySelector, capacity),
                static (source, state, observer) => GroupByCore(source, observer, (o, d) => AsyncObserver.GroupBy(o, d, state.keySelector, state.capacity)));
        }

        public static IAsyncObservable<IGroupedAsyncObservable<TKey, TSource>> GroupBy<TSource, TKey>(this IAsyncObservable<TSource> source, Func<TSource, TKey> keySelector, int capacity, IEqualityComparer<TKey> comparer)
        {
            if (source == null)
                throw new ArgumentNullException(nameof(source));
            if (keySelector == null)
                throw new ArgumentNullException(nameof(keySelector));
            if (capacity < 0)
                throw new ArgumentOutOfRangeException(nameof(capacity));
            if (comparer == null)
                throw new ArgumentNullException(nameof(comparer));

            return CreateAsyncObservable<IGroupedAsyncObservable<TKey, TSource>>.From(
                source,
                (keySelector, capacity, comparer),
                static (source, state, observer) => GroupByCore(source, observer, (o, d) => AsyncObserver.GroupBy(o, d, state.keySelector, state.capacity, state.comparer)));
        }

        public static IAsyncObservable<IGroupedAsyncObservable<TKey, TElement>> GroupBy<TSource, TKey, TElement>(this IAsyncObservable<TSource> source, Func<TSource, TKey> keySelector, Func<TSource, TElement> elementSelector)
        {
            if (source == null)
                throw new ArgumentNullException(nameof(source));
            if (keySelector == null)
                throw new ArgumentNullException(nameof(keySelector));
            if (elementSelector == null)
                throw new ArgumentNullException(nameof(elementSelector));

            return CreateAsyncObservable<IGroupedAsyncObservable<TKey, TElement>>.From(
                source,

View on GitHub (pinned to 94b5d5ab91)