dotnet/reactive · error · ArgumentNullException

Value cannot be null. (Parameter 'second')

Error message

Value cannot be null. (Parameter 'second')

What it means

SequenceEqual compares two observables element-by-element; the second sequence is validated because the pairwise comparison is impossible without it. Fix: pass a non-null IAsyncObservable<TSource> for the second argument.

Solutions

  1. Pass a valid IAsyncObservable<TSource> as the second argument.
  2. Default null to an empty sequence: second ?? AsyncObservable.Empty<TSource>().
  3. Null-check the second sequence and handle the absent case explicitly.
  4. Trace where the second sequence is produced and fix the producer returning null.

Example fix

// before
var eq = left.SequenceEqual(maybeRight);
// after
var eq = left.SequenceEqual(maybeRight ?? AsyncObservable.Empty<int>());
Defensive patterns

Strategy: validation

Validate before calling

second ??= AsyncObservable.Empty<TSource>();

Type guard

static bool HasSequence<TSource>(IAsyncObservable<TSource>? s) => s is not null;

Try / catch

try { var eq = first.SequenceEqual(second); }
catch (ArgumentNullException ex) when (ex.ParamName == "second") { /* treat as not-equal or empty */ }

Prevention

When it happens

Trigger: Calling first.SequenceEqual(null) or first.SequenceEqual((IAsyncObservable<TSource>)null) where the right-hand sequence comes from a nullable source.

Common situations: Comparing against a sequence retrieved from a nullable API (config, cache, another operator's result); forgetting that a variable of reference type defaults to null.

Related errors


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

Appendix: source

Thrown at AsyncRx.NET/System.Reactive.Async/Linq/Operators/SequenceEqual.cs:20

// The .NET Foundation licenses this file to you under the MIT License.
// See the LICENSE file in the project root for more information. 

using System.Collections.Generic;
using System.Reactive.Disposables;
using System.Threading;

namespace System.Reactive.Linq
{
    public partial class AsyncObservable
    {
        // TODO: Add SequenceEqual<T>(IAsyncObservable<T>, IAsyncEnumerable<T>).

        public static IAsyncObservable<bool> SequenceEqual<TSource>(this IAsyncObservable<TSource> first, IAsyncObservable<TSource> second)
        {
            if (first == null)
                throw new ArgumentNullException(nameof(first));
            if (second == null)
                throw new ArgumentNullException(nameof(second));

            return CreateAsyncObservable<bool>.From(
                first,
                second,
                static async (first, second, observer) =>
                {
                    var (firstObserver, secondObserver) = AsyncObserver.SequenceEqual<TSource>(observer);

                    var firstTask = first.SubscribeSafeAsync(firstObserver);
                    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);
                });

View on GitHub (pinned to 94b5d5ab91)