dotnet/reactive · error · ArgumentNullException
keySelector
Error message
keySelector
What it means
Observable.MaxBy throws ArgumentNullException when the keySelector delegate passed to it is null. Rx operators validate all arguments eagerly at call time, before returning the observable, so the exception is thrown synchronously rather than surfaced through the subscription. keySelector is required because MaxBy must compute a comparison key for each element to find the maximum elements.
Solutions
- Pass a valid non-null lambda or method group as keySelector, e.g. source.MaxBy(x => x.Priority).
- If the selector comes from a variable, check it for null before calling MaxBy and throw a descriptive error or substitute a default selector.
- Fix the initialization of the field/property/config value that supplies the selector so it is never null.
Example fix
// before Func<Order, int> selector = config?.OrderSelector; var max = orders.MaxBy(selector); // NRE/ArgumentNullException if config is null // after var max = orders.MaxBy(o => o.Total); // or: orders.MaxBy(selector ?? (o => o.Total))
Defensive patterns
Strategy: validation
Validate before calling
if (source == null) throw new ArgumentNullException(nameof(source)); if (keySelector == null) throw new ArgumentNullException(nameof(keySelector)); var max = source.MaxBy(keySelector);
Type guard
bool HasSelector<T, TKey>(Func<T, TKey> selector) => selector is not null;
Try / catch
try { var max = source.MaxBy(keySelector); }
catch (ArgumentNullException ex) when (ex.ParamName == "keySelector") { /* supply default selector or log */ } Prevention
- Never store key selectors in nullable fields; pass lambdas directly at the call site.
- When resolving selectors dynamically, fail fast with a clear error at resolution time.
- Enable nullable reference types (LangVersion 8+ #nullable enable) so nullable delegates surface at compile time.
When it happens
Trigger: Calling Observable.MaxBy(source, null) — the two-argument overload (IObservable<TSource>, Func<TSource,TKey>) at Observable.Aggregates.cs:1556 with a null second argument, e.g. MaxBy(x => someSelector) where someSelector is an uninitialized field or a failed lookup.
Common situations: Storing the key selector in a field or dictionary that was never initialized; dynamically resolving the selector from config/dependency injection and getting null; refactoring code so the lambda was replaced by a nullable delegate variable.
Related errors
- Value cannot be null. (Parameter 'keySelector')
- Value cannot be null. (Parameter 'comparer')
- Value cannot be null. (Parameter 'first')
- Value cannot be null. (Parameter 'second')
- Value cannot be null. (Parameter 'third')
AI-assisted analysis of dotnet/reactive@94b5d5ab91 (2026-09-15).
Data as JSON: /api/errors/8b64dfc8c29de6ca.
Report an issue: GitHub.
Appendix: source
Thrown at Rx.NET/Source/src/System.Reactive/Linq/Observable.Aggregates.cs:1556
/// Returns the elements in an observable sequence with the maximum key value.
/// </summary>
/// <typeparam name="TSource">The type of the elements in the source sequence.</typeparam>
/// <typeparam name="TKey">The type of the key computed for each element in the source sequence.</typeparam>
/// <param name="source">An observable sequence to get the maximum elements for.</param>
/// <param name="keySelector">Key selector function.</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"/> 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)
{
if (source == null)
{
throw new ArgumentNullException(nameof(source));
}
if (keySelector == null)
{
throw new ArgumentNullException(nameof(keySelector));
}
return s_impl.MaxBy(source, keySelector);
}
/// <summary>
/// Returns the elements in an observable sequence with the maximum key value according to the specified comparer.
/// </summary>
/// <typeparam name="TSource">The type of the elements in the source sequence.</typeparam>
/// <typeparam name="TKey">The type of the key computed for each element in the source sequence.</typeparam>
/// <param name="source">An observable sequence to get the maximum elements for.</param>
/// <param name="keySelector">Key selector function.</param>
/// <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)
{View on GitHub (pinned to 94b5d5ab91)