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
- Pass a valid IAsyncObservable<TSource> as the second argument.
- Default null to an empty sequence: second ?? AsyncObservable.Empty<TSource>().
- Null-check the second sequence and handle the absent case explicitly.
- 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
- Coalesce nullable right-hand sequences to AsyncObservable.Empty before comparing.
- Keep expected/reference sequences in non-nullable fields initialized eagerly.
- Add unit tests covering the null-second-sequence path.
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
- Value cannot be null. (Parameter 'first')
- Value cannot be null. (Parameter 'comparer')
- Value cannot be null. (Parameter 'observer')
- Value cannot be null. (Parameter 'scheduler')
- Value cannot be null. (Parameter 'source')
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)