{"record":{"id":"20531a5d4566c744","repo":"dotnet/reactive","slug":"oncompleted-observable-extensions","errorCode":null,"errorMessage":"onCompleted","messagePattern":"onCompleted","errorType":"exception","errorClass":"ArgumentNullException","httpStatus":null,"severity":"error","filePath":"Rx.NET/Source/src/System.Reactive/Observable.Extensions.cs","lineNumber":121,"sourceCode":"        /// <param name=\"onNext\">Action to invoke for each element in the observable sequence.</param>\n        /// <param name=\"onCompleted\">Action to invoke upon graceful termination of the observable sequence.</param>\n        /// <returns><see cref=\"IDisposable\"/> object used to unsubscribe from the observable sequence.</returns>\n        /// <exception cref=\"ArgumentNullException\"><paramref name=\"source\"/> or <paramref name=\"onNext\"/> or <paramref name=\"onCompleted\"/> is <c>null</c>.</exception>\n        public static IDisposable Subscribe<T>(this IObservable<T> source, Action<T> onNext, Action 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 (onCompleted == null)\n            {\n                throw new ArgumentNullException(nameof(onCompleted));\n            }\n\n            //\n            // [OK] Use of unsafe Subscribe: non-pretentious constructor for an observer; this overload is not to be used internally.\n            //\n            return source.Subscribe/*Unsafe*/(new AnonymousObserver<T>(onNext, Stubs.Throw, onCompleted));\n        }\n\n        /// <summary>\n        /// Subscribes an element handler, an exception handler, and a completion handler to an observable sequence.\n        /// </summary>\n        /// <typeparam name=\"T\">The type of the elements in the source sequence.</typeparam>\n        /// <param name=\"source\">Observable sequence to subscribe to.</param>\n        /// <param name=\"onNext\">Action to invoke for each element in the observable sequence.</param>\n        /// <param name=\"onError\">Action to invoke upon exceptional termination of the observable sequence.</param>\n        /// <param name=\"onCompleted\">Action to invoke upon graceful termination of the observable sequence.</param>\n        /// <returns><see cref=\"IDisposable\"/> object used to unsubscribe from the observable sequence.</returns>\n        /// <exception cref=\"ArgumentNullException\"><paramref name=\"source\"/> or <paramref name=\"onNext\"/> or <paramref name=\"onError\"/> or <paramref name=\"onCompleted\"/> is <c>null</c>.</exception>","sourceCodeStart":103,"sourceCodeEnd":139,"githubUrl":"https://github.com/dotnet/reactive/blob/94b5d5ab912789f5abe9a72138a25bbd716fe59c/Rx.NET/Source/src/System.Reactive/Observable.Extensions.cs#L103-L139","documentation":"The Subscribe(source, onNext, onCompleted) overload throws ArgumentNullException with ParamName \"onCompleted\" when the onCompleted Action is null. Rx validates it eagerly since AnonymousObserver needs a concrete completion handler; internally the error slot is filled with Stubs.Throw.","triggerScenarios":"Calling source.Subscribe(onNext, null) intending to skip completion handling, or passing an Action variable that was never assigned.","commonSituations":"Assuming optional trailing arguments may be null (they cannot, despite C# optional-parameter habits); refactoring that removed the completion lambda but kept the call; dynamic handler registration failing to produce the action.","solutions":["Pass a non-null onCompleted delegate, e.g. () => { } if completion is irrelevant.","Use the onNext+onError overload if completion handling is truly unnecessary (it stubs onCompleted for you).","Ensure the completion callback is initialized before subscribing."],"exampleFix":"// before\nsource.Subscribe(x => Handle(x), null); // ArgumentNullException: onCompleted\n\n// after\nsource.Subscribe(x => Handle(x), () => Console.WriteLine(\"done\"));","handlingStrategy":"validation","validationCode":"if (onCompleted is null) onCompleted = () => { }; // or use Subscribe(onNext, onError) overload","typeGuard":"static bool HasHandlers<T>(Action<T> onNext, Action onCompleted) => onNext is not null && onCompleted is not null;","tryCatchPattern":"try { disposable = source.Subscribe(onNext, onCompleted); }\ncatch (ArgumentNullException ex) when (ex.ParamName == \"onCompleted\") { /* supply no-op completion handler */ }","preventionTips":["Remember Rx delegates are not optional parameters; never pass null in place of a handler.","Use Subscribe(onNext, onError) when completion handling is not needed.","Default completion callbacks to no-op lambdas in shared subscription helpers."],"tags":["null-argument","rx","subscribe","callback"],"backgroundTag":"null-argument","analyzedSha":"94b5d5ab912789f5abe9a72138a25bbd716fe59c","analyzedAt":"2026-09-15T02:26:24.759Z","contentChangedAt":"2026-09-15T02:26:24.759Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}