{"record":{"id":"0bf7fc9d6a21df50","repo":"dotnet/reactive","slug":"value-cannot-be-null-parameter-first-observable-multiple-zip","errorCode":null,"errorMessage":"Value cannot be null. (Parameter 'first')","messagePattern":"Value cannot be null\\. \\(Parameter 'first'\\)","errorType":"validation","errorClass":"ArgumentNullException","httpStatus":null,"severity":"error","filePath":"Rx.NET/Source/src/System.Reactive/Linq/Observable.Multiple.Zip.cs","lineNumber":1198,"sourceCode":"    }\n\n#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.\n    public static partial class ObservableEx\n#pragma warning restore CA1711\n    {\n        /// <summary>\n        /// 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.\n        /// </summary>\n        /// <typeparam name=\"TFirst\">The type of the elements in the first source sequence.</typeparam>\n        /// <typeparam name=\"TSecond\">The type of the elements in the second source sequence.</typeparam>\n        /// <param name=\"first\">First observable source.</param>\n        /// <param name=\"second\">Second observable source.</param>\n        /// <returns>An observable sequence containing the result of combining elements of the sources using tuple values.</returns>\n        /// <exception cref=\"ArgumentNullException\"><paramref name=\"first\"/> or <paramref name=\"second\"/> is null.</exception>\n        public static IObservable<(TFirst First, TSecond Second)> Zip<TFirst, TSecond>(this IObservable<TFirst> first, IObservable<TSecond> second)\n        {\n            if (first == null)\n                throw new ArgumentNullException(nameof(first));\n            if (second == null)\n                throw new ArgumentNullException(nameof(second));\n\n            return s_impl.Zip(first, second);\n        }\n\n        /// <summary>\n        /// 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.\n        /// </summary>\n        /// <typeparam name=\"TFirst\">The type of the elements in the first source sequence.</typeparam>\n        /// <typeparam name=\"TSecond\">The type of the elements in the second source sequence.</typeparam>\n        /// <typeparam name=\"TThird\">The type of the elements in the third source sequence.</typeparam>\n        /// <param name=\"first\">First observable source.</param>\n        /// <param name=\"second\">Second observable source.</param>\n        /// <param name=\"third\">Third observable source.</param>\n        /// <returns>An observable sequence containing the result of combining elements of the sources using tuple values.</returns>\n        /// <exception cref=\"ArgumentNullException\"><paramref name=\"first\"/> or <paramref name=\"second\"/> or <paramref name=\"third\"/> is null.</exception>\n        public static IObservable<(TFirst First, TSecond Second, TThird Third)> Zip<TFirst, TSecond, TThird>(this IObservable<TFirst> first, IObservable<TSecond> second, IObservable<TThird> third)","sourceCodeStart":1180,"sourceCodeEnd":1216,"githubUrl":"https://github.com/dotnet/reactive/blob/94b5d5ab912789f5abe9a72138a25bbd716fe59c/Rx.NET/Source/src/System.Reactive/Linq/Observable.Multiple.Zip.cs#L1180-L1216","documentation":"ArgumentNullException (Parameter 'first'): the two-argument tuple-returning Observable.Zip overload received a null first source. Rx validates both inputs (first, then second) before delegating to the internal implementation, throwing eagerly so callers learn at the call site that a null is not a valid observable sequence.","triggerScenarios":"Calling first.Zip(second) with first == null — usually an uninitialized IObservable field, a method returning null instead of Observable.Empty/Never, or chaining Zip on the result of an API that can return null.","commonSituations":"Legacy wrappers that return null observables, LINQ-style pipelines where an earlier operator returned null instead of a sequence, unit tests stubbing subjects as null.","solutions":["Ensure the receiver/first argument is a constructed IObservable<T> before calling Zip.","Return Observable.Empty<T>() or Observable.Never<T>() instead of null from producers.","Coalesce at the call site: (maybeFirst ?? Observable.Empty<T>()).Zip(second).","Add caller-side null checks or Debug.Assert to catch producers returning null."],"exampleFix":"// before\nIObservable<int> first = GetSource(); // may return null\nvar zipped = first.Zip(second);\n// after\nvar zipped = (first ?? Observable.Empty<int>()).Zip(second);","handlingStrategy":"validation","validationCode":"if (first == null) throw new ArgumentNullException(nameof(first));\nif (second == null) throw new ArgumentNullException(nameof(second));\n// call-site coalescing:\nvar zipped = (first ?? Observable.Empty<TFirst>()).Zip(second ?? Observable.Empty<TSecond>());","typeGuard":"static bool IsObservable<T>([NotNullWhen(true)] IObservable<T>? o) => o is not null;\nif (IsObservable(first) && IsObservable(second)) { /* safe to Zip */ }","tryCatchPattern":"try\n{\n    var zipped = first.Zip(second);\n}\ncatch (ArgumentNullException ex) when (ex.ParamName == nameof(first))\n{\n    logger.LogError(ex, \"first source was null when calling Zip\");\n}","preventionTips":["Ensure all producer methods return non-null IObservable<T>; use Empty/Never for absence.","Never chain operators directly on APIs that may return null — coalesce first.","Enable C# nullable reference types so null receivers are flagged at compile time.","In wrappers around legacy code, normalize nulls to Observable.Empty before returning."],"tags":["null-argument","rxjs","zip","argument-validation"],"backgroundTag":"null-argument","analyzedSha":"94b5d5ab912789f5abe9a72138a25bbd716fe59c","analyzedAt":"2026-09-15T02:26:24.759Z","contentChangedAt":"2026-09-15T02:26:24.759Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}