dotnet/reactive · error · ArgumentNullException

Value cannot be null. (Parameter 'second')

Error message

Value cannot be null. (Parameter 'second')

What it means

Catch(first, second) subscribes to 'first' and, if it fails, re-subscribes to 'second'. The extension method validates both arguments up front; passing a null 'second' means there is no fallback source, so System.Reactive.Async throws ArgumentNullException before any subscription happens.

Solutions

  1. Ensure the fallback observable is created before calling Catch (e.g. AsyncObservable.Empty<TSource>() instead of null)
  2. Check the expression producing 'second' for a code path that returns null
  3. Add a null check or ?? AsyncObservable.Empty<TSource>() at the call site

Example fix

// before
var result = primary.Catch(GetFallback()); // GetFallback() may return null
// after
var fallback = GetFallback() ?? AsyncObservable.Empty<int>();
var result = primary.Catch(fallback);
Defensive patterns

Strategy: validation

Validate before calling

if (first is null) throw new ArgumentNullException(nameof(first));
if (second is null) throw new ArgumentNullException(nameof(second));

Type guard

bool IsValid<T>(IAsyncObservable<T> first, IAsyncObservable<T> second) => first != null && second != null;

Try / catch

try { var result = first.Catch(second); } catch (ArgumentNullException ex) { /* ex.ParamName == "second"; supply a real fallback */ }

Prevention

When it happens

Trigger: Calling the two-source overload Catch(first, second) with a null second observable, e.g. a factory method or dictionary lookup that returned null instead of a valid IAsyncObservable<TSource>.

Common situations: Conditional fallback chains where a secondary stream is only assigned when a feature is enabled, DI containers resolving the fallback as null, or caching/lookup code returning null for the retry source.

Related errors


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

Appendix: source

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

            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);

        public static IAsyncObservable<TSource> Catch<TSource>(this IEnumerable<IAsyncObservable<TSource>> sources)
        {

View on GitHub (pinned to 94b5d5ab91)