dotnet/reactive · error · ArgumentNullException

ArgumentNullException (default message: Value cannot be…

Error message

ArgumentNullException (default message: Value cannot be null. (Parameter 'keySelector'))

What it means

The Distinct(source, keySelector) overload requires a non-null keySelector because Distinct uses it to extract deduplication keys for its internal set; a null keySelector throws ArgumentNullException with Parameter 'keySelector' after source validation passes.

Solutions

  1. Provide the key selector lambda directly, e.g., x => x.Id
  2. If you truly need no projection, use the comparer-less Distinct() overload instead of a null selector
  3. Null-check the selector where it is produced before forwarding
  4. Fix configuration/DI that should supply the selector

Example fix

// before
Func<Item, int> sel = _selector; // may be null
var result = source.Distinct(sel);
// after
var result = source.Distinct(x => x.Id);
Defensive patterns

Strategy: validation

Validate before calling

if (keySelector is null) throw new ArgumentNullException(nameof(keySelector));
// or: keySelector ??= x => x.DefaultKey;

Type guard

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

Try / catch

try { var result = source.Distinct(keySelector); }
catch (ArgumentNullException ex) when (ex.ParamName == "keySelector")
{
    result = source.Distinct(); // default equality without projection
}

Prevention

When it happens

Trigger: Calling Distinct<TSource, TKey>(source, null) — valid source, null Func<TSource, TKey>.

Common situations: Storing the key selector in a variable that was never assigned, or receiving it as a null method parameter and forwarding it unchecked.

Related errors


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

Appendix: source

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

        /// Returns an observable sequence that contains only distinct elements according to the keySelector.
        /// </summary>
        /// <typeparam name="TSource">The type of the elements in the source sequence.</typeparam>
        /// <typeparam name="TKey">The type of the discriminator key computed for each element in the source sequence.</typeparam>
        /// <param name="source">An observable sequence to retain distinct elements for.</param>
        /// <param name="keySelector">A function to compute the comparison key for each element.</param>
        /// <returns>An observable sequence only containing the distinct elements, based on a computed key value, from the source sequence.</returns>
        /// <exception cref="ArgumentNullException"><paramref name="source"/> or <paramref name="keySelector"/> is null.</exception>
        /// <remarks>Usage of this operator should be considered carefully due to the maintenance of an internal lookup structure which can grow large.</remarks>
        public static IObservable<TSource> Distinct<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.Distinct(source, keySelector);
        }

        /// <summary>
        /// Returns an observable sequence that contains only distinct elements according to the keySelector and the comparer.
        /// </summary>
        /// <typeparam name="TSource">The type of the elements in the source sequence.</typeparam>
        /// <typeparam name="TKey">The type of the discriminator key computed for each element in the source sequence.</typeparam>
        /// <param name="source">An observable sequence to retain distinct elements for.</param>
        /// <param name="keySelector">A function to compute the comparison key for each element.</param>
        /// <param name="comparer">Equality comparer for source elements.</param>
        /// <returns>An observable sequence only containing the distinct elements, based on a computed key value, from the source sequence.</returns>
        /// <exception cref="ArgumentNullException"><paramref name="source"/> or <paramref name="keySelector"/> or <paramref name="comparer"/> is null.</exception>
        /// <remarks>Usage of this operator should be considered carefully due to the maintenance of an internal lookup structure which can grow large.</remarks>
        public static IObservable<TSource> Distinct<TSource, TKey>(this IObservable<TSource> source, Func<TSource, TKey> keySelector, IEqualityComparer<TKey> comparer)
        {

View on GitHub (pinned to 94b5d5ab91)