dotnet/reactive · error · ArgumentNullException
Value cannot be null. (Parameter 'comparer')
Error message
Value cannot be null. (Parameter 'comparer')
What it means
The comparer-based SequenceEqual overload requires a non-null IEqualityComparer<TSource>; a null comparer throws ArgumentNullException with parameter 'comparer'. Unlike LINQ-to-Objects, this library does not default a null comparer to EqualityComparer<T>.Default.
Solutions
- Pass an explicit comparer, e.g. EqualityComparer<TSource>.Default or Comparer-based lambda wrapper.
- Coalesce the comparer: comparer ?? EqualityComparer<TSource>.Default.
- Fix the DI registration or factory so the comparer is always provided.
- If the comparer is truly optional, call the two-argument SequenceEqual overload instead.
Example fix
// before var eq = left.SequenceEqual(right, options.Comparer); // options.Comparer is null // after var eq = left.SequenceEqual(right, options.Comparer ?? EqualityComparer<string>.Default);
Defensive patterns
Strategy: validation
Validate before calling
comparer ??= EqualityComparer<TSource>.Default;
Type guard
static bool HasComparer<T>(IEqualityComparer<T>? c) => c is not null;
Try / catch
try { var eq = left.SequenceEqual(right, comparer); }
catch (ArgumentNullException ex) when (ex.ParamName == "comparer") { var eq2 = left.SequenceEqual(right); /* default comparer */ } Prevention
- Default optional comparer parameters to EqualityComparer<T>.Default, never null.
- Verify DI registrations for comparer services at startup.
- Prefer the two-argument overload when no custom comparer is needed.
When it happens
Trigger: Calling first.SequenceEqual(second, null) where the comparer comes from an optional parameter, DI-resolved service, or config-driven selection that yielded null.
Common situations: Optional comparer parameters defaulted to null instead of EqualityComparer<TSource>.Default; dependency-injected comparer not registered; settings key missing so the comparer factory returns null.
Related errors
- Value cannot be null. (Parameter 'comparer')
- Value cannot be null. (Parameter 'first')
- Value cannot be null. (Parameter 'second')
- Value cannot be null. (Parameter 'observer')
- Value cannot be null. (Parameter 'scheduler')
AI-assisted analysis of dotnet/reactive@94b5d5ab91 (2026-09-15).
Data as JSON: /api/errors/cd9e284d854e1ebd.
Report an issue: GitHub.
Appendix: source
Thrown at AsyncRx.NET/System.Reactive.Async/Linq/Operators/SequenceEqual.cs:48
var secondTask = second.SubscribeSafeAsync(secondObserver);
// REVIEW: Consider concurrent subscriptions.
var d1 = await firstTask.ConfigureAwait(false);
var d2 = await secondTask.ConfigureAwait(false);
return StableCompositeAsyncDisposable.Create(d1, d2);
});
}
public static IAsyncObservable<bool> SequenceEqual<TSource>(this IAsyncObservable<TSource> first, IAsyncObservable<TSource> second, IEqualityComparer<TSource> comparer)
{
if (first == null)
throw new ArgumentNullException(nameof(first));
if (second == null)
throw new ArgumentNullException(nameof(second));
if (comparer == null)
throw new ArgumentNullException(nameof(comparer));
return CreateAsyncObservable<bool>.From(
first,
(second, comparer),
static async (first, state, observer) =>
{
var (firstObserver, secondObserver) = AsyncObserver.SequenceEqual(observer, state.comparer);
var firstTask = first.SubscribeSafeAsync(firstObserver);
var secondTask = state.second.SubscribeSafeAsync(secondObserver);
// REVIEW: Consider concurrent subscriptions.
var d1 = await firstTask.ConfigureAwait(false);
var d2 = await secondTask.ConfigureAwait(false);
return StableCompositeAsyncDisposable.Create(d1, d2);
});View on GitHub (pinned to 94b5d5ab91)