dotnet/reactive · error · ArgumentNullException

Value cannot be null. (Parameter 'source13')

Error message

Value cannot be null. (Parameter 'source13')

What it means

This error is thrown by the generated 14-source overload of the Zip extension operator in System.Reactive.Async when the 14th source observable (source13, 0-based 13th) is null. The generated Zip overloads eagerly validate every IAsyncObservable argument and the result selector before creating the operator pipeline, so a null argument fails immediately with ArgumentNullException instead of failing later during subscription.

Solutions

  1. Check which Zip overload you are calling and verify every source argument, especially position 14, is non-null before invoking
  2. If a source may legitimately be missing, substitute AsyncObservable.Empty<T>() or a default observable instead of null
  3. Move the call into a guarded helper that validates all sources with a loop before calling Zip
  4. Enable nullable reference types (C# 8 #nullable enable) so the compiler flags a possibly-null source at the call site

Example fix

// before
var result = sources[0].Zip(sources[1], sources[2], sources[3], sources[4], sources[5], sources[6], sources[7], sources[8], sources[9], sources[10], sources[11], sources[12], sources[13], sources[14], selector);
// after
var result = sources[0].Zip(sources[1], sources[2], sources[3], sources[4], sources[5], sources[6], sources[7], sources[8], sources[9], sources[10], sources[11], sources[12], sources[13], sources[14] ?? AsyncObservable.Empty<T14>(), selector);
Defensive patterns

Strategy: validation

Validate before calling

if (source13 == null) throw new ArgumentException("The 14th source passed to Zip must not be null.");

Type guard

static bool IsValidSource<T>(IAsyncObservable<T> source) => source is not null;

Try / catch

try
{
    var zipped = s1.Zip(s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, s12, s13, s14, selector);
}
catch (ArgumentNullException ex) when (ex.ParamName == "source13")
{
    logger.LogError(ex, "Zip: 14th source observable was null");
}

Prevention

When it happens

Trigger: Calling AsyncObservableExtensions.Zip with 14+ sources where the 14th IAsyncObservable argument is null, e.g. Zip(s1, s2, ..., s13, null, selector) with a Func<...,ValueTask<TResult>> selector. Any of the ten overloads sharing these generated checks behaves identically.

Common situations: Passing the result of a lookup or dictionary access that returned null as one of the zipped sources; building the source list programmatically and one element being missing; refactoring from fewer to more zipped sources and misaligning argument positions.

Related errors


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

Appendix: source

Thrown at AsyncRx.NET/System.Reactive.Async/Linq/Operators/Zip.Generated.cs:1533

                throw new ArgumentNullException(nameof(source4));
            if (source5 == null)
                throw new ArgumentNullException(nameof(source5));
            if (source6 == null)
                throw new ArgumentNullException(nameof(source6));
            if (source7 == null)
                throw new ArgumentNullException(nameof(source7));
            if (source8 == null)
                throw new ArgumentNullException(nameof(source8));
            if (source9 == null)
                throw new ArgumentNullException(nameof(source9));
            if (source10 == null)
                throw new ArgumentNullException(nameof(source10));
            if (source11 == null)
                throw new ArgumentNullException(nameof(source11));
            if (source12 == null)
                throw new ArgumentNullException(nameof(source12));
            if (source13 == null)
                throw new ArgumentNullException(nameof(source13));
            if (source14 == null)
                throw new ArgumentNullException(nameof(source14));
            if (selector == null)
                throw new ArgumentNullException(nameof(selector));

            return Create<TResult>(async observer =>
            {
                var d = new CompositeAsyncDisposable();

                var (observer1, observer2, observer3, observer4, observer5, observer6, observer7, observer8, observer9, observer10, observer11, observer12, observer13, observer14) = AsyncObserver.Zip(observer, selector);

                var sub1 = source1.SubscribeSafeAsync(observer1).AsTask().ContinueWith(disposable => d.AddAsync(disposable.Result).AsTask()).Unwrap();
                var sub2 = source2.SubscribeSafeAsync(observer2).AsTask().ContinueWith(disposable => d.AddAsync(disposable.Result).AsTask()).Unwrap();
                var sub3 = source3.SubscribeSafeAsync(observer3).AsTask().ContinueWith(disposable => d.AddAsync(disposable.Result).AsTask()).Unwrap();
                var sub4 = source4.SubscribeSafeAsync(observer4).AsTask().ContinueWith(disposable => d.AddAsync(disposable.Result).AsTask()).Unwrap();
                var sub5 = source5.SubscribeSafeAsync(observer5).AsTask().ContinueWith(disposable => d.AddAsync(disposable.Result).AsTask()).Unwrap();
                var sub6 = source6.SubscribeSafeAsync(observer6).AsTask().ContinueWith(disposable => d.AddAsync(disposable.Result).AsTask()).Unwrap();
                var sub7 = source7.SubscribeSafeAsync(observer7).AsTask().ContinueWith(disposable => d.AddAsync(disposable.Result).AsTask()).Unwrap();

View on GitHub (pinned to 94b5d5ab91)