{"record":{"id":"d3bfa1fab8290239","repo":"dotnet/reactive","slug":"value-cannot-be-null-parameter-onerror-observable","errorCode":null,"errorMessage":"Value cannot be null. (Parameter 'onError')","messagePattern":"Value cannot be null\\. \\(Parameter 'onError'\\)","errorType":"validation","errorClass":"ArgumentNullException","httpStatus":null,"severity":"error","filePath":"Rx.NET/Source/src/System.Reactive/Linq/Observable.StandardSequenceOperators.cs","lineNumber":1385,"sourceCode":"        /// <param name=\"onError\">A transform function to apply when an error occurs in the source sequence.</param>\n        /// <param name=\"onCompleted\">A transform function to apply when the end of the source sequence is reached.</param>\n        /// <returns>An observable sequence whose elements are the result of invoking the one-to-many transform function corresponding to each notification in the input sequence.</returns>\n        /// <exception cref=\"ArgumentNullException\"><paramref name=\"source\"/> or <paramref name=\"onNext\"/> or <paramref name=\"onError\"/> or <paramref name=\"onCompleted\"/> is null.</exception>\n        public static IObservable<TResult> SelectMany<TSource, TResult>(this IObservable<TSource> source, Func<TSource, IObservable<TResult>> onNext, Func<Exception, IObservable<TResult>> onError, Func<IObservable<TResult>> onCompleted)\n        {\n            if (source == null)\n            {\n                throw new ArgumentNullException(nameof(source));\n            }\n\n            if (onNext == null)\n            {\n                throw new ArgumentNullException(nameof(onNext));\n            }\n\n            if (onError == null)\n            {\n                throw new ArgumentNullException(nameof(onError));\n            }\n\n            if (onCompleted == null)\n            {\n                throw new ArgumentNullException(nameof(onCompleted));\n            }\n\n            return s_impl.SelectMany(source, onNext, onError, onCompleted);\n        }\n\n        /// <summary>\n        /// Projects each notification of an observable sequence to an observable sequence by incorporating the element's index and merges the resulting observable sequences into one observable sequence.\n        /// </summary>\n        /// <typeparam name=\"TSource\">The type of the elements in the source sequence.</typeparam>\n        /// <typeparam name=\"TResult\">The type of the elements in the projected inner sequences and the elements in the merged result sequence.</typeparam>\n        /// <param name=\"source\">An observable sequence of notifications to project.</param>\n        /// <param name=\"onNext\">A transform function to apply to each element; the second parameter of the function represents the index of the source element.</param>\n        /// <param name=\"onError\">A transform function to apply when an error occurs in the source sequence.</param>","sourceCodeStart":1367,"sourceCodeEnd":1403,"githubUrl":"https://github.com/dotnet/reactive/blob/94b5d5ab912789f5abe9a72138a25bbd716fe59c/Rx.NET/Source/src/System.Reactive/Linq/Observable.StandardSequenceOperators.cs#L1367-L1403","documentation":"Thrown by the notification-based SelectMany(source, onNext, onError, onCompleted) overload when the onError delegate (Func<Exception, IObservable<TResult>>) is null. Unlike Subscribe, SelectMany cannot accept a null error handler because errors must be translated into a result sequence; validation throws immediately.","triggerScenarios":"Calling Observable.SelectMany(source, onNext, null, onCompleted) — the error-to-observable mapping is null, e.g. the developer assumed error handling is optional as it is with Subscribe.","commonSituations":"Migrating code from Subscribe to SelectMany while keeping the Subscribe null-handler convention; scaffolding where only the happy path was written and error handling stubbed as null.","solutions":["Pass an error mapping lambda, e.g. ex => Observable.Throw<TResult>(ex), to propagate errors unchanged.","Pass ex => Observable.Empty<TResult>() to swallow errors into an empty sequence (use with care).","Use a logging handler that returns Observable.Throw after recording the exception."],"exampleFix":"// before\nvar q = source.SelectMany(x => Load(x), null, () => Observable.Empty<Item>());\n\n// after\nvar q = source.SelectMany(x => Load(x), ex => Observable.Throw<Item>(ex), () => Observable.Empty<Item>());","handlingStrategy":"validation","validationCode":"if (onError is null) onError = static ex => Observable.Throw<TResult>(ex); // or throw before the call","typeGuard":"static bool ErrorMapperPresent<TResult>(Func<Exception, IObservable<TResult>> onError)\n    => onError is not null;","tryCatchPattern":"try\n{\n    var q = source.SelectMany(onNext, onError, onCompleted);\n}\ncatch (ArgumentNullException ex) when (ex.ParamName == \"onError\")\n{\n    // default: propagate errors unchanged\n    q = source.SelectMany(onNext, static ex => Observable.Throw<TResult>(ex), onCompleted);\n}","preventionTips":["Standardize on ex => Observable.Throw<TResult>(ex) as the default error mapper in your codebase.","Never leave error handlers null when porting Subscribe code to operator pipelines.","Wrap Rx operators in project-specific extension helpers that fill default handlers."],"tags":["null-argument","argument-validation","reactive-extensions","linq"],"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"}