dotnet/reactive · error · ArgumentNullException

ArgumentNullException

Error message

ArgumentNullException

What it means

In the single-keySelector GroupBy overload, this throw fires when the keySelector Func<TSource, TKey> is null. GroupBy delegates to s_impl.GroupBy only after all arguments are validated, so the exception surfaces synchronously at the operator call, with Parameter 'keySelector' in the message.

Solutions

  1. Pass a valid key selector lambda, e.g. x => x.Category
  2. Guard the selector before the call and throw a descriptive exception if null
  3. Fix the upstream factory that produced the null Func

Example fix

// before
Func<Order, string> keySel = config.KeySelector; // null when config missing
var groups = orders.GroupBy(keySel);
// after
var groups = orders.GroupBy(keySel ?? (o => o.DefaultKey));
Defensive patterns

Strategy: validation

Validate before calling

if (keySelector == null) throw new ArgumentNullException(nameof(keySelector));
var groups = source.GroupBy(keySelector);

Type guard

bool HasSelector<T,TKey>(Func<T,TKey> sel) => sel is not null;

Try / catch

try { var groups = source.GroupBy(keySelector); }
catch (ArgumentNullException ex) when (ex.ParamName == "keySelector") { /* selector was null; apply default grouping */ }

Prevention

When it happens

Trigger: Calling source.GroupBy(null) directly, or passing a method-group/expression variable that was never assigned (e.g. a Func<T,TKey> field defaulting to null).

Common situations: Building the key selector dynamically from configuration and the config value is missing; generics-heavy code where a null Func is passed through several layers before reaching GroupBy.

Related errors


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

Appendix: source

Thrown at Rx.NET/Source/src/System.Reactive/Linq/Observable.StandardSequenceOperators.cs:197

        /// <summary>
        /// Groups the elements of an observable sequence according to a specified key selector function.
        /// </summary>
        /// <typeparam name="TSource">The type of the elements in the source sequence.</typeparam>
        /// <typeparam name="TKey">The type of the grouping key computed for each element in the source sequence.</typeparam>
        /// <param name="source">An observable sequence whose elements to group.</param>
        /// <param name="keySelector">A function to extract the key for each element.</param>
        /// <returns>A sequence of observable groups, each of which corresponds to a unique key value, containing all elements that share that same key value.</returns>
        /// <exception cref="ArgumentNullException"><paramref name="source"/> or <paramref name="keySelector"/> is null.</exception>
        public static IObservable<IGroupedObservable<TKey, TSource>> GroupBy<TSource, TKey>(this IObservable<TSource> source, Func<TSource, TKey> keySelector)
        {
            if (source == null)
            {
                throw new ArgumentNullException(nameof(source));
            }

            if (keySelector == null)
            {
                throw new ArgumentNullException(nameof(keySelector));
            }

            return s_impl.GroupBy(source, keySelector);
        }

        /// <summary>
        /// Groups the elements of an observable sequence according to a specified key selector function and comparer.
        /// </summary>
        /// <typeparam name="TSource">The type of the elements in the source sequence.</typeparam>
        /// <typeparam name="TKey">The type of the grouping key computed for each element in the source sequence.</typeparam>
        /// <param name="source">An observable sequence whose elements to group.</param>
        /// <param name="keySelector">A function to extract the key for each element.</param>
        /// <param name="comparer">An equality comparer to compare keys with.</param>
        /// <returns>A sequence of observable groups, each of which corresponds to a unique key value, containing all elements that share that same key value.</returns>
        /// <exception cref="ArgumentNullException"><paramref name="source"/> or <paramref name="keySelector"/> or <paramref name="comparer"/> is null.</exception>
        public static IObservable<IGroupedObservable<TKey, TSource>> GroupBy<TSource, TKey>(this IObservable<TSource> source, Func<TSource, TKey> keySelector, IEqualityComparer<TKey> comparer)
        {
            if (source == null)

View on GitHub (pinned to 94b5d5ab91)