dotnet/reactive · error · ArgumentNullException
Value cannot be null. (Parameter 'second')
Error message
Value cannot be null. (Parameter 'second')
What it means
System.Reactive's public Zip<TFirst, TSecond> extension method explicitly validates its arguments before delegating to the internal implementation, throwing ArgumentNullException when the second source sequence is null. Rx operators require non-null sources because the internal pipeline calls Subscribe on every sequence and cannot recover from a null. This is an immediate, fail-fast argument validation, not a runtime failure of the query.
Solutions
- Ensure the second observable is assigned before calling Zip (check for uninitialized/failed factory results).
- Substitute Observable.Empty<TSecond>() or Observable.Never<TSecond>() when 'no sequence' is the intended semantic.
- Wrap the call site in a null check and throw a meaningful domain-specific error or log which source was missing.
Example fix
// before var zipped = xs.Zip(ys); // ys is null // after var zipped = xs.Zip(ys ?? Observable.Empty<int>());
Defensive patterns
Strategy: validation
Validate before calling
if (first == null) throw new ArgumentNullException(nameof(first)); if (second == null) throw new ArgumentNullException(nameof(second)); var zipped = first.Zip(second);
Type guard
bool IsNonNull<T>(IObservable<T> s) => s is not null;
Try / catch
try { var zipped = first.Zip(second); }
catch (ArgumentNullException ex) when (ex.ParamName == "second") { /* log and use fallback source */ } Prevention
- Never let factory/lookup methods return null observables; return Observable.Empty instead.
- Null-check all source sequences before composing multi-source queries.
- Use nullable reference types (IObservable<T>?) to surface unassigned streams at compile time.
When it happens
Trigger: Calling Observable.Zip(first, null) or IObservable.Zip(first, second) where the second IObservable<TSecond> variable is null (e.g. an uninitialized field, a failed lookup, or a method returned null instead of Observable.Empty).
Common situations: Passing a sequence obtained from a dictionary lookup or optional dependency that turned out to be null; a factory method returning null instead of an empty observable; refactoring that removed a default sequence assignment.
Related errors
- Value cannot be null. (Parameter 'third')
- Value cannot be null. (Parameter 'fourth')
- null (Parameter 'scheduler')
- null (Parameter 'values')
- Value cannot be null. (Parameter 'observer')
AI-assisted analysis of dotnet/reactive@94b5d5ab91 (2026-09-15).
Data as JSON: /api/errors/8bdcebbb607a652e.
Report an issue: GitHub.
Appendix: source
Thrown at Rx.NET/Source/src/System.Reactive/Linq/Observable.Multiple.Zip.cs:1200
#pragma warning disable CA1711 // (Don't use Ex suffix.) This has been a public type for many years, so we can't rename it now.
public static partial class ObservableEx
#pragma warning restore CA1711
{
/// <summary>
/// Merges the specified observable sequences into one observable sequence of tuple values whenever all of the observable sequences have produced an element at a corresponding index.
/// </summary>
/// <typeparam name="TFirst">The type of the elements in the first source sequence.</typeparam>
/// <typeparam name="TSecond">The type of the elements in the second source sequence.</typeparam>
/// <param name="first">First observable source.</param>
/// <param name="second">Second observable source.</param>
/// <returns>An observable sequence containing the result of combining elements of the sources using tuple values.</returns>
/// <exception cref="ArgumentNullException"><paramref name="first"/> or <paramref name="second"/> is null.</exception>
public static IObservable<(TFirst First, TSecond Second)> Zip<TFirst, TSecond>(this IObservable<TFirst> first, IObservable<TSecond> second)
{
if (first == null)
throw new ArgumentNullException(nameof(first));
if (second == null)
throw new ArgumentNullException(nameof(second));
return s_impl.Zip(first, second);
}
/// <summary>
/// Merges the specified observable sequences into one observable sequence of tuple values whenever all of the observable sequences have produced an element at a corresponding index.
/// </summary>
/// <typeparam name="TFirst">The type of the elements in the first source sequence.</typeparam>
/// <typeparam name="TSecond">The type of the elements in the second source sequence.</typeparam>
/// <typeparam name="TThird">The type of the elements in the third source sequence.</typeparam>
/// <param name="first">First observable source.</param>
/// <param name="second">Second observable source.</param>
/// <param name="third">Third observable source.</param>
/// <returns>An observable sequence containing the result of combining elements of the sources using tuple values.</returns>
/// <exception cref="ArgumentNullException"><paramref name="first"/> or <paramref name="second"/> or <paramref name="third"/> is null.</exception>
public static IObservable<(TFirst First, TSecond Second, TThird Third)> Zip<TFirst, TSecond, TThird>(this IObservable<TFirst> first, IObservable<TSecond> second, IObservable<TThird> third)
{
if (first == null)View on GitHub (pinned to 94b5d5ab91)