dotnet/reactive · error · ArgumentNullException
ArgumentNullException(nameof(keySelector))
Error message
ArgumentNullException(nameof(keySelector))
What it means
System.ArgumentNullException with ParamName 'keySelector' thrown by AsyncObserver.DistinctUntilChanged<TSource,TKey>(IAsyncObserver<TSource>, Func<TSource, ValueTask<TKey>>) when the async key selector is null. The selector must produce a ValueTask<TKey> per element for consecutive-difference comparison.
Solutions
- Provide a valid async selector: async x => (ValueTask<TKey>)ComputeKeyAsync(x).
- Switch to the synchronous selector overload if no async work is needed.
- Initialize the delegate before composing the observer.
Example fix
// before Func<Event, ValueTask<string>> key = null; var o = AsyncObserver.DistinctUntilChanged<Event, string>(observer, key); // after var o = AsyncObserver.DistinctUntilChanged<Event, string>(observer, async e => await ResolveKeyAsync(e));
Defensive patterns
Strategy: validation
Validate before calling
if (asyncKeySelector is null) throw new ArgumentNullException(nameof(asyncKeySelector)); var obs = AsyncObserver.DistinctUntilChanged<T, TKey>(observer, asyncKeySelector);
Type guard
bool IsValidAsyncSelector<TSource, TKey>(Func<TSource, ValueTask<TKey>>? f) => f is not null;
Try / catch
try
{
var obs = AsyncObserver.DistinctUntilChanged<T, TKey>(observer, asyncKeySelector);
}
catch (ArgumentNullException ex) when (ex.ParamName == "keySelector")
{
var obs = AsyncObserver.DistinctUntilChanged<T, TKey>(observer, x => x.DefaultKey);
} Prevention
- Bind async selectors to concrete async methods, not nullable delegate fields
- Prefer the synchronous selector overload when no I/O is required
- Fail fast at startup if a configured selector fails to resolve
When it happens
Trigger: Calling AsyncObserver.DistinctUntilChanged<TSource,TKey>(observer, (Func<TSource, ValueTask<TKey>>)null).
Common situations: Async delegate resolved from config/registry was null; overload mismatch left the parameter bound to a null lambda variable; refactor dropped the selector assignment.
Related errors
- ArgumentNullException(nameof(observer))
- observer
- Argument cannot be null (Parameter name: observer)
- Argument cannot be null (Parameter name: predicate)
- Argument cannot be null (Parameter name: predicate)
AI-assisted analysis of dotnet/reactive@94b5d5ab91 (2026-09-15).
Data as JSON: /api/errors/85a87ce85d429c0f.
Report an issue: GitHub.
Appendix: source
Thrown at AsyncRx.NET/System.Reactive.Async/Linq/Operators/DistinctUntilChanged.cs:125
return DistinctUntilChanged(observer, x => x, comparer);
}
public static IAsyncObserver<TSource> DistinctUntilChanged<TSource, TKey>(IAsyncObserver<TSource> observer, Func<TSource, TKey> keySelector)
{
if (observer == null)
throw new ArgumentNullException(nameof(observer));
if (keySelector == null)
throw new ArgumentNullException(nameof(keySelector));
return DistinctUntilChanged(observer, keySelector, EqualityComparer<TKey>.Default);
}
public static IAsyncObserver<TSource> DistinctUntilChanged<TSource, TKey>(IAsyncObserver<TSource> observer, Func<TSource, ValueTask<TKey>> keySelector)
{
if (observer == null)
throw new ArgumentNullException(nameof(observer));
if (keySelector == null)
throw new ArgumentNullException(nameof(keySelector));
return DistinctUntilChanged(observer, keySelector, EqualityComparer<TKey>.Default);
}
public static IAsyncObserver<TSource> DistinctUntilChanged<TSource, TKey>(IAsyncObserver<TSource> observer, Func<TSource, TKey> keySelector, IEqualityComparer<TKey> comparer)
{
if (observer == null)
throw new ArgumentNullException(nameof(observer));
if (keySelector == null)
throw new ArgumentNullException(nameof(keySelector));
if (comparer == null)
throw new ArgumentNullException(nameof(comparer));
var hasCurrentKey = false;
var currentKey = default(TKey);
return Create<TSource>(
async x =>View on GitHub (pinned to 94b5d5ab91)