dotnet/reactive · error · ArgumentNullException

Value cannot be null. (Parameter 'comparer')

Error message

Value cannot be null. (Parameter 'comparer')

What it means

The comparer overload of Observable.MaxBy throws ArgumentNullException when the IComparer<TKey> comparer argument is null. The comparer is mandatory in this overload because it replaces the default Comparer<TKey>.Default used by the two-argument overload; without it no ordering can be established.

Solutions

  1. Pass a valid comparer, e.g. Comparer<TKey>.Default if you actually want default semantics, or a custom Comparer<TKey>.Create(...).
  2. Use the two-argument MaxBy overload if you do not need a custom comparer.
  3. Null-check the comparer before the call and fall back to Comparer<TKey>.Default.

Example fix

// before
obs.MaxBy(x => x.Name, config.Comparer); // Comparer property is null
// after
obs.MaxBy(x => x.Name, config.Comparer ?? Comparer<string>.Default);
Defensive patterns

Strategy: validation

Validate before calling

var cmp = comparer ?? Comparer<TKey>.Default;
var r = source.MaxBy(keySelector, cmp);

Type guard

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

Try / catch

try { var r = source.MaxBy(sel, cmp); }
catch (ArgumentNullException ex) when (ex.ParamName == "comparer") { var r = source.MaxBy(sel); }

Prevention

When it happens

Trigger: Calling Observable.MaxBy(source, keySelector, null) at Observable.Aggregates.cs:1587 with a null third argument, e.g. a comparer resolved from configuration or a service that returned null.

Common situations: A custom IComparer<T> instance held in a nullable field never assigned; a factory method returning null when comparison rules are unconfigured; switching from the two-argument to the three-argument overload and passing null intending 'default comparer'.

Related errors


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

Appendix: source

Thrown at Rx.NET/Source/src/System.Reactive/Linq/Observable.Aggregates.cs:1587

        /// <param name="comparer">Comparer used to compare key values.</param>
        /// <returns>An observable sequence containing a list of zero or more elements that have a maximum key value.</returns>
        /// <exception cref="ArgumentNullException"><paramref name="source"/> or <paramref name="keySelector"/> or <paramref name="comparer"/> is null.</exception>
        /// <remarks>The return type of this operator differs from the corresponding operator on IEnumerable in order to retain asynchronous behavior.</remarks>
        public static IObservable<IList<TSource>> MaxBy<TSource, TKey>(this IObservable<TSource> source, Func<TSource, TKey> keySelector, IComparer<TKey> comparer)
        {
            if (source == null)
            {
                throw new ArgumentNullException(nameof(source));
            }

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

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

            return s_impl.MaxBy(source, keySelector, comparer);
        }

        #endregion

        #region + Min +

        /// <summary>
        /// Returns the minimum element in an observable sequence.
        /// </summary>
        /// <typeparam name="TSource">The type of the elements in the source sequence.</typeparam>
        /// <param name="source">An observable sequence to determine the minimum element of.</param>
        /// <returns>An observable sequence containing a single element with the minimum element in the source sequence.</returns>
        /// <exception cref="ArgumentNullException"><paramref name="source"/> is null.</exception>
        /// <remarks>The return type of this operator differs from the corresponding operator on IEnumerable in order to retain asynchronous behavior.</remarks>
        public static IObservable<TSource> Min<TSource>(this IObservable<TSource> source)

View on GitHub (pinned to 94b5d5ab91)