dotnet/reactive · error · ArgumentNullException

Value cannot be null. (Parameter 'second')

Error message

Value cannot be null. (Parameter 'second')

What it means

The two-sequence overload Catch<TSource>(first, second) throws ArgumentNullException with parameter name 'second' when the fallback sequence is null. The second sequence is concatenated when the first fails, so it must be non-null; validation happens eagerly at call time.

Solutions

  1. Pass Enumerable.Empty<TSource>() for an empty fallback instead of null.
  2. Check why the fallback expression evaluated to null and fix the producer.
  3. Coalesce: first.Catch(second ?? Enumerable.Empty<T>()).
  4. Enable nullable reference types to catch it at compile time.

Example fix

// before
var result = primary.Catch((IEnumerable<int>)null);
// after
var result = primary.Catch(Enumerable.Empty<int>());
Defensive patterns

Strategy: validation

Validate before calling

if (second is null)
    throw new ArgumentNullException(nameof(second));
// or coalesce:
second ??= Enumerable.Empty<TSource>();

Type guard

static bool HasFallback<TSource>(IEnumerable<TSource> s) => s != null;

Try / catch

try
{
    var result = first.Catch(second);
}
catch (ArgumentNullException ex) when (ex.ParamName == "second")
{
    var result = first.Catch(Enumerable.Empty<TSource>());
}

Prevention

When it happens

Trigger: Calling first.Catch(second) with null as the second (fallback) sequence.

Common situations: A fallback obtained from a lookup or factory that returned null; assuming null means 'empty fallback' instead of Enumerable.Empty<T>(); refactoring that dropped the fallback assignment.

Related errors


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

Appendix: source

Thrown at Ix.NET/Source/System.Interactive/System/Linq/Operators/Catch.cs:71

            if (sources == null)
                throw new ArgumentNullException(nameof(sources));

            return CatchCore(sources);
        }

        /// <summary>
        /// Creates a sequence that returns the elements of the first sequence, switching to the second in case of an error.
        /// </summary>
        /// <typeparam name="TSource">Source sequence element type.</typeparam>
        /// <param name="first">First sequence.</param>
        /// <param name="second">Second sequence, concatenated to the result in case the first sequence completes exceptionally.</param>
        /// <returns>The first sequence, followed by the second sequence in case an error is produced.</returns>
        public static IEnumerable<TSource> Catch<TSource>(this IEnumerable<TSource> first, IEnumerable<TSource> second)
        {
            if (first == null)
                throw new ArgumentNullException(nameof(first));
            if (second == null)
                throw new ArgumentNullException(nameof(second));

            return CatchCore(new[] { first, second });
        }

        private static IEnumerable<TSource> CatchCore<TSource, TException>(IEnumerable<TSource> source, Func<TException, IEnumerable<TSource>> handler)
            where TException : Exception
        {
            var err = default(IEnumerable<TSource>);

            using (var e = source.GetEnumerator())
            {
                while (true)
                {
                    TSource c;

                    try
                    {
                        if (!e.MoveNext())

View on GitHub (pinned to 94b5d5ab91)