dotnet/reactive · error · ArgumentNullException

Value cannot be null. (Parameter 'source8')

Error message

Value cannot be null. (Parameter 'source8')

What it means

AsyncRx.NET's 8-ary Zip operator validates every source before building the observable pipeline. Passing null for the eighth IAsyncObservable source causes an ArgumentNullException with Parameter 'source8'. The library fails fast at call time because a null source would otherwise break subscription logic deep inside AsyncObserver.Zip.

Solutions

  1. Initialize source8 to a valid IAsyncObservable<T8> before calling Zip (e.g. AsyncObservable.Empty<T8>()).
  2. Check the expression producing source8 for accidental null returns (failed lookups, uninitialized fields).
  3. Add a guard or default-substitute (?? AsyncObservable.Empty<T8>()) at the call site.
  4. If sources are in a collection, assert the collection has no null elements before spreading into Zip.

Example fix

// before
var zipped = s1.Zip(s2, s3, s4, s5, s6, s7, lookup8, (a,b,c,d,e,f,g,h) => a+h);
// after
var s8 = lookup8 ?? AsyncObservable.Empty<T8>();
var zipped = s1.Zip(s2, s3, s4, s5, s6, s7, s8, (a,b,c,d,e,f,g,h) => a+h);
Defensive patterns

Strategy: validation

Validate before calling

if (source8 == null)
    throw new InvalidOperationException("Zip requires a non-null source8");
// or default it: var s8 = maybeSource8 ?? AsyncObservable.Empty<T8>();

Type guard

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

Try / catch

try
{
    var zipped = s1.Zip(s2, s3, s4, s5, s6, s7, s8, selector);
}
catch (ArgumentNullException ex) when (ex.ParamName == "source8")
{
    // fall back to empty-source pipeline or log configuration error
}

Prevention

When it happens

Trigger: Calling source1.Zip(source2, ..., source8) where the eighth argument is null - e.g. a dictionary lookup, conditional expression, or method returning null was passed as source8.

Common situations: Building source lists dynamically (arrays or LINQ projections containing nulls), refactoring code where a source factory started returning null, or optional stream wiring where one of eight inputs was never initialized.

Related errors


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

Appendix: source

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

        public static IAsyncObservable<(T1, T2, T3, T4, T5, T6, T7, T8)> Zip<T1, T2, T3, T4, T5, T6, T7, T8>(this IAsyncObservable<T1> source1, IAsyncObservable<T2> source2, IAsyncObservable<T3> source3, IAsyncObservable<T4> source4, IAsyncObservable<T5> source5, IAsyncObservable<T6> source6, IAsyncObservable<T7> source7, IAsyncObservable<T8> source8)
        {
            if (source1 == null)
                throw new ArgumentNullException(nameof(source1));
            if (source2 == null)
                throw new ArgumentNullException(nameof(source2));
            if (source3 == null)
                throw new ArgumentNullException(nameof(source3));
            if (source4 == null)
                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));

            return Create<(T1, T2, T3, T4, T5, T6, T7, T8)>(async observer =>
            {
                var d = new CompositeAsyncDisposable();

                var (observer1, observer2, observer3, observer4, observer5, observer6, observer7, observer8) = AsyncObserver.Zip(observer);

                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();
                var sub8 = source8.SubscribeSafeAsync(observer8).AsTask().ContinueWith(disposable => d.AddAsync(disposable.Result).AsTask()).Unwrap();

                await Task.WhenAll(sub1, sub2, sub3, sub4, sub5, sub6, sub7, sub8).ConfigureAwait(false);

View on GitHub (pinned to 94b5d5ab91)