dotnet/reactive · error · ArgumentNullException
Value cannot be null. (Parameter 'source7')
Error message
Value cannot be null. (Parameter 'source7')
What it means
This ArgumentNullException is thrown by the 8-source overload's sibling (the 7-source Zip) when the seventh observable source is null. Rx.NET's Zip eagerly validates every argument before subscribing, because a null IObservable would otherwise fail later inside the query pipeline with a less-diagnosable NullReferenceException. The parameter name is embedded in the message via nameof(source7).
Solutions
- Ensure the seventh argument passed to Zip is a non-null IObservable<T>; initialize it or use Observable.Empty<TSource7>() as a placeholder.
- Check the expression producing source7 (factory method, dictionary lookup, conditional assignment) for paths that yield null.
- If a variable number of sources is needed, validate all sources before calling Zip, or use the array-based Observable.Zip overload that accepts IObservable<T>[] and guards there.
- Fail fast: add a null check with a meaningful error message at the call site before composing the query.
Example fix
// before var merged = Observable.Zip(s1, s2, s3, s4, s5, s6, streams.Count > 6 ? streams[6] : null, (a, b, c, d, e, f, g) => g); // after var s7 = streams.Count > 6 ? streams[6] : Observable.Empty<TSource7>(); var merged = Observable.Zip(s1, s2, s3, s4, s5, s6, s7, (a, b, c, d, e, f, g) => g);
Defensive patterns
Strategy: validation
Validate before calling
if (source7 == null)
throw new InvalidOperationException("source7 must be provided before calling Zip");
var zipped = Observable.Zip(s1, s2, s3, s4, s5, s6, source7, selector); Type guard
static bool IsValidSource<T>(IObservable<T> s) => s is not null;
Try / catch
try
{
var zipped = Observable.Zip(s1, s2, s3, s4, s5, s6, s7, selector);
}
catch (ArgumentNullException ex) when (ex.ParamName == "source7")
{
logger.LogError(ex, "Zip called with null source7");
return Observable.Empty<TResult>();
} Prevention
- Never pass raw nullable observables into Zip; coalesce with Observable.Empty<T>().
- Validate all sources in one guard clause before composing the query.
- Prefer Observable.Concat/empty placeholders over null for 'optional' streams.
When it happens
Trigger: Calling Observable.Zip(source1..source7, resultSelector) (the 7-argument overload in Observable.Multiple.Zip.cs) with source7 == null; the check at line 260 runs after source1-source6 validation passes.
Common situations: Building source arrays or tuples programmatically where the last element was never initialized; passing a method that returns IObservable<T> and forgetting it can return null on a fallback path; refactoring from a lower-arity Zip overload and leaving the last source unwired; deserializing a set of streams where one stream is absent.
Related errors
- Value cannot be null. (Parameter 'source8')
- Value cannot be null. (Parameter 'sixth')
- conversion
- addHandler
- removeHandler
AI-assisted analysis of dotnet/reactive@94b5d5ab91 (2026-09-15).
Data as JSON: /api/errors/7e2c165ba8a78a1e.
Report an issue: GitHub.
Appendix: source
Thrown at Rx.NET/Source/src/System.Reactive/Linq/Observable.Multiple.Zip.cs:260
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 (resultSelector == null)
{
throw new ArgumentNullException(nameof(resultSelector));
}
return s_impl.Zip(source1, source2, source3, source4, source5, source6, source7, resultSelector);
}
/// <summary>
/// Merges the specified observable sequences into one observable sequence by using the selector function whenever all of the observable sequences have produced an element at a corresponding index.
/// </summary>
/// <typeparam name="TSource1">The type of the elements in the first source sequence.</typeparam>
/// <typeparam name="TSource2">The type of the elements in the second source sequence.</typeparam>
/// <typeparam name="TSource3">The type of the elements in the third source sequence.</typeparam>
/// <typeparam name="TSource4">The type of the elements in the fourth source sequence.</typeparam>
/// <typeparam name="TSource5">The type of the elements in the fifth source sequence.</typeparam>View on GitHub (pinned to 94b5d5ab91)