dotnet/reactive · error · ArgumentNullException

Value cannot be null. (Parameter 'first')

Error message

Value cannot be null. (Parameter 'first')

What it means

The two-sequence Catch(first, second) overload switches to second when first fails; a null first argument throws ArgumentNullException via the guard clause. Both operands are mandatory so the operator always has a stream to subscribe and a fallback.

Solutions

  1. Ensure first is non-null; substitute AsyncObservable.Empty<TSource>(scheduler) when there is no primary
  2. Reorder logic so second-only is expressed with second directly (or Empty as first) instead of null
  3. Null-check the primary producer before composing Catch

Example fix

// before
var result = AsyncObservable.Catch<int>(primaryStream, backup); // primaryStream is null
// after
var result = AsyncObservable.Catch<int>(primaryStream ?? AsyncObservable.Empty<int>(Scheduler.Default), backup);
Defensive patterns

Strategy: validation

Validate before calling

if (first == null) throw new InvalidOperationException("Catch(first, second) requires a non-null first observable");
if (second == null) throw new InvalidOperationException("Catch(first, second) requires a non-null second observable");

Type guard

bool IsObservable<T>(IAsyncObservable<T> s) => s is not null;

Try / catch

try { var result = first.Catch(second); }
catch (ArgumentNullException ex) when (ex.ParamName is "first" or "second") { /* substitute Empty for the null operand */ }

Prevention

When it happens

Trigger: Calling Catch<TSource>(null, second) via static syntax, or chaining .Catch(second) on a null first observable.

Common situations: Primary stream from a connection/factory that returned null; merging Catch composition where an earlier variable was never assigned; optional primary sources treated as always-present.

Related errors


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

Appendix: source

Thrown at AsyncRx.NET/System.Reactive.Async/Linq/Operators/Catch.cs:60

                throw new ArgumentNullException(nameof(handler));

            return Create(
                source,
                handler,
                static async (source, handler, observer) =>
                {
                    var (sink, inner) = AsyncObserver.Catch(observer, handler);

                    var subscription = await source.SubscribeSafeAsync(sink).ConfigureAwait(false);

                    return StableCompositeAsyncDisposable.Create(subscription, inner);
                });
        }

        public static IAsyncObservable<TSource> Catch<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 Create(
                first,
                second,
                static async (first, second, observer) =>
                {
                    var (sink, inner) = AsyncObserver.Catch(observer, second);

                    var subscription = await first.SubscribeSafeAsync(sink).ConfigureAwait(false);

                    return StableCompositeAsyncDisposable.Create(subscription, inner);
                });
        }

        public static IAsyncObservable<TSource> Catch<TSource>(params IAsyncObservable<TSource>[] sources) => Catch((IEnumerable<IAsyncObservable<TSource>>)sources);

View on GitHub (pinned to 94b5d5ab91)