dotnet/reactive · error · ArgumentNullException

Value cannot be null. (Parameter 'keySelector')

Error message

Value cannot be null. (Parameter 'keySelector')

What it means

The DistinctUntilChanged(source, keySelector) overload requires a non-null Func<TSource,TKey> used to compute comparison keys, and throws ArgumentNullException for a null keySelector. Validation is eager: the exception is thrown when the operator method is invoked, before any element is processed. This prevents a NullReferenceException deep inside the enumeration.

Solutions

  1. Pass an explicit identity key selector: DistinctUntilChanged(source, x => x) if you intended element comparison.
  2. If the selector is optional in your API, default it to x => x instead of null before calling.
  3. Null-check the delegate at your API boundary and throw a descriptive exception.
  4. Fix the delegate producer (factory/DI/lookup) that returned null.

Example fix

// before
Func<Order, int> key = config.Mode == "customer" ? o => o.CustomerId : null;
var distinct = orders.DistinctUntilChanged(key);
// after
Func<Order, int> key = config.Mode == "customer" ? o => o.CustomerId : (Func<Order, int>)(o => o.Id);
var distinct = orders.DistinctUntilChanged(key);
Defensive patterns

Strategy: validation

Validate before calling

if (keySelector is null) keySelector = static x => x; // or reject with a clear message
var result = source.DistinctUntilChanged(keySelector);

Type guard

static bool HasSelector<TSource,TKey>(Func<TSource,TKey>? f) => f is not null;

Try / catch

try
{
    var result = source.DistinctUntilChanged(keySelector);
}
catch (ArgumentNullException ex) when (ex.ParamName == "keySelector")
{
    result = source.DistinctUntilChanged(x => x);
}

Prevention

When it happens

Trigger: Calling DistinctUntilChanged(source, keySelector) where the keySelector lambda/expression reference is null — most often when it is stored in a variable, field, or passed as a method parameter that was null, or a lookup of delegates returns null.

Common situations: Strategy/predicate injection where a delegate was never assigned, overloads confusion (passing null intending to select the whole element), reflection-built pipelines where an optional keySelector defaults to null.

Related errors


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

Appendix: source

Thrown at Ix.NET/Source/System.Interactive/System/Linq/Operators/DistinctUntilChanged.cs:55

                throw new ArgumentNullException(nameof(comparer));

            return DistinctUntilChangedCore(source, x => x, comparer);
        }

        /// <summary>
        /// Returns consecutive distinct elements based on a key value by using the specified equality comparer to compare key values.
        /// </summary>
        /// <typeparam name="TSource">Source sequence element type.</typeparam>
        /// <typeparam name="TKey">Key type.</typeparam>
        /// <param name="source">Source sequence.</param>
        /// <param name="keySelector">Key selector.</param>
        /// <returns>Sequence without adjacent non-distinct elements.</returns>
        public static IEnumerable<TSource> DistinctUntilChanged<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector)
        {
            if (source == null)
                throw new ArgumentNullException(nameof(source));
            if (keySelector == null)
                throw new ArgumentNullException(nameof(keySelector));

            return DistinctUntilChangedCore(source, keySelector, EqualityComparer<TKey>.Default);
        }

        /// <summary>
        /// Returns consecutive distinct elements based on a key value by using the specified equality comparer to compare key values.
        /// </summary>
        /// <typeparam name="TSource">Source sequence element type.</typeparam>
        /// <typeparam name="TKey">Key type.</typeparam>
        /// <param name="source">Source sequence.</param>
        /// <param name="keySelector">Key selector.</param>
        /// <param name="comparer">Comparer used to compare key values.</param>
        /// <returns>Sequence without adjacent non-distinct elements.</returns>
        public static IEnumerable<TSource> DistinctUntilChanged<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, IEqualityComparer<TKey> comparer)
        {
            if (source == null)
                throw new ArgumentNullException(nameof(source));
            if (keySelector == null)

View on GitHub (pinned to 94b5d5ab91)