dotnet/reactive · error · ArgumentNullException

Value cannot be null. (Parameter 'first')

Error message

Value cannot be null. (Parameter 'first')

What it means

SequenceEqual(this first, second) validates both source sequences up front. A null first observable makes the comparison meaningless, so the operator throws ArgumentNullException named 'first' before any subscription occurs.

Solutions

  1. Ensure the receiver expression is non-null before calling SequenceEqual.
  2. If the first sequence may be absent, substitute AsyncObservable.Empty<TSource>().
  3. Guard with a null check and throw a more meaningful exception or return a known result.
  4. Fix the upstream factory so it never returns null (return an empty observable instead).

Example fix

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

Strategy: validation

Validate before calling

if (first is null) first = AsyncObservable.Empty<TSource>();
if (second is null) 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 == "first") { /* handle missing left sequence */ }

Prevention

When it happens

Trigger: Invoking firstObservable.SequenceEqual(secondObservable) where firstObservable is null — typically the result of a factory/lookup method that returned null and is chained with the extension-call syntax.

Common situations: Chaining .SequenceEqual(...) onto a method that can return null (cache miss, dictionary TryGetValue ignored); test fixtures building sequences conditionally.

Related errors


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

Appendix: source

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

// Licensed to the .NET Foundation under one or more agreements.
// 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);

View on GitHub (pinned to 94b5d5ab91)