dotnet/reactive · error · ArgumentNullException

Value cannot be null. (Parameter 'comparer')

Error message

Value cannot be null. (Parameter 'comparer')

What it means

The comparer overload of AsyncObservable.ToHashSet requires a non-null IEqualityComparer<TSource> used to build the internal HashSet and to deduplicate incoming elements. Passing null throws ArgumentNullException(Parameter 'comparer') synchronously at the call site.

Solutions

  1. Call the parameterless ToHashSet(source) overload when default equality is desired.
  2. Pass EqualityComparer<TSource>.Default explicitly instead of null.
  3. Fix the comparer construction so it returns a real instance rather than null.

Example fix

// before
var res = source.ToHashSet(comparer); // comparer is null
// after
var res = comparer != null ? source.ToHashSet(comparer) : source.ToHashSet();
Defensive patterns

Strategy: validation

Validate before calling

if (comparer == null) comparer = EqualityComparer<TSource>.Default;

Type guard

bool IsValidComparer<T>(IEqualityComparer<T> c) => c is not null;

Try / catch

try { var set = await source.ToHashSet(comparer); } catch (ArgumentNullException ex) when (ex.ParamName == "comparer") { /* retry with default comparer */ }

Prevention

When it happens

Trigger: Calling ToHashSet(source, comparer) with comparer = null, typically a comparer variable that failed to initialize or a ternary that fell through to null.

Common situations: Injecting a comparer via DI that was not registered; loading a comparer from configuration; passing null intending to mean 'use default comparer' instead of calling the parameterless overload.

Related errors


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

Appendix: source

Thrown at AsyncRx.NET/System.Reactive.Async/Linq/Operators/ToHashSet.cs:24

namespace System.Reactive.Linq
{
    public partial class AsyncObservable
    {
        public static IAsyncObservable<HashSet<TSource>> ToHashSet<TSource>(this IAsyncObservable<TSource> source)
        {
            if (source == null)
                throw new ArgumentNullException(nameof(source));

            return Create<TSource, HashSet<TSource>>(source, static (source, observer) => source.SubscribeSafeAsync(AsyncObserver.ToHashSet(observer)));
        }

        public static IAsyncObservable<HashSet<TSource>> ToHashSet<TSource>(this IAsyncObservable<TSource> source, IEqualityComparer<TSource> comparer)
        {
            if (source == null)
                throw new ArgumentNullException(nameof(source));
            if (comparer == null)
                throw new ArgumentNullException(nameof(comparer));

            return CreateAsyncObservable<HashSet<TSource>>.From(
                source,
                comparer,
                static (source, comparer, observer) => source.SubscribeSafeAsync(AsyncObserver.ToHashSet(observer, comparer)));
        }
    }

    public partial class AsyncObserver
    {
        public static IAsyncObserver<TSource> ToHashSet<TSource>(IAsyncObserver<HashSet<TSource>> observer)
        {
            if (observer == null)
                throw new ArgumentNullException(nameof(observer));

            return ToHashSet(observer, EqualityComparer<TSource>.Default);
        }

View on GitHub (pinned to 94b5d5ab91)