{"record":{"id":"93b2ada1e96f81cc","repo":"dotnet/reactive","slug":"value-cannot-be-null-parameter-oncompletedasync","errorCode":null,"errorMessage":"Value cannot be null. (Parameter 'onCompletedAsync')","messagePattern":"Value cannot be null\\. \\(Parameter 'onCompletedAsync'\\)","errorType":"validation","errorClass":"ArgumentNullException","httpStatus":null,"severity":"error","filePath":"AsyncRx.NET/System.Reactive.Async/AsyncObservableExtensions.cs","lineNumber":41,"sourceCode":"        {\n            if (source == null)\n                throw new ArgumentNullException(nameof(source));\n            if (onNextAsync == null)\n                throw new ArgumentNullException(nameof(onNextAsync));\n            if (onErrorAsync == null)\n                throw new ArgumentNullException(nameof(onErrorAsync));\n\n            return source.SubscribeAsync(new AsyncObserver<T>(onNextAsync, onErrorAsync, () => default));\n        }\n\n        public static ValueTask<IAsyncDisposable> SubscribeAsync<T>(this IAsyncObservable<T> source, Func<T, ValueTask> onNextAsync, Func<ValueTask> onCompletedAsync)\n        {\n            if (source == null)\n                throw new ArgumentNullException(nameof(source));\n            if (onNextAsync == null)\n                throw new ArgumentNullException(nameof(onNextAsync));\n            if (onCompletedAsync == null)\n                throw new ArgumentNullException(nameof(onCompletedAsync));\n\n            return source.SubscribeAsync(new AsyncObserver<T>(onNextAsync, ex => new ValueTask(Task.FromException(ex)), onCompletedAsync));\n        }\n\n        public static ValueTask<IAsyncDisposable> SubscribeAsync<T>(this IAsyncObservable<T> source, Func<T, ValueTask> onNextAsync, Func<Exception, ValueTask> onErrorAsync, Func<ValueTask> onCompletedAsync)\n        {\n            if (source == null)\n                throw new ArgumentNullException(nameof(source));\n            if (onNextAsync == null)\n                throw new ArgumentNullException(nameof(onNextAsync));\n            if (onErrorAsync == null)\n                throw new ArgumentNullException(nameof(onErrorAsync));\n            if (onCompletedAsync == null)\n                throw new ArgumentNullException(nameof(onCompletedAsync));\n\n            return source.SubscribeAsync(new AsyncObserver<T>(onNextAsync, onErrorAsync, onCompletedAsync));\n        }\n","sourceCodeStart":23,"sourceCodeEnd":59,"githubUrl":"https://github.com/dotnet/reactive/blob/94b5d5ab912789f5abe9a72138a25bbd716fe59c/AsyncRx.NET/System.Reactive.Async/AsyncObservableExtensions.cs#L23-L59","documentation":"This ArgumentNullException is thrown by the SubscribeAsync extension method when the onCompletedAsync delegate is null. AsyncRx.NET validates all observer callbacks up front so that a null handler fails fast at subscription time instead of throwing a NullReferenceException when the source completes. Every parameter of SubscribeAsync is required because the underlying AsyncObserver needs all three handlers.","triggerScenarios":"Calling source.SubscribeAsync(source, onNextAsync, onCompletedAsync) (the two-delegate overload) with null as the completion callback, e.g. SubscribeAsync(src, async x => await Handle(x), null).","commonSituations":"Developers porting from Rx.NET where OnCompleted can be omitted, or building handlers conditionally where the completion lambda ends up null after an if-statement, or passing optional Func<ValueTask> parameters straight through.","solutions":["Pass a no-op completion handler: () => new ValueTask() or () => default.","Use a simpler overload such as SubscribeAsync(source, onNextAsync) which supplies default error/completion handlers for you.","Audit the call site for a variable that is null before being passed as onCompletedAsync."],"exampleFix":"// before\nawait source.SubscribeAsync(async x => await Handle(x), null);\n// after\nawait source.SubscribeAsync(async x => await Handle(x), () => default);","handlingStrategy":"validation","validationCode":"if (onCompletedAsync == null) throw new ArgumentNullException(nameof(onCompletedAsync));\nawait source.SubscribeAsync(onNextAsync, onCompletedAsync);","typeGuard":"bool IsValidHandlers(Func<T, ValueTask> next, Func<ValueTask> completed) => next != null && completed != null;","tryCatchPattern":"try\n{\n    await source.SubscribeAsync(onNextAsync, onCompletedAsync);\n}\ncatch (ArgumentNullException ex) when (ex.ParamName == \"onCompletedAsync\")\n{\n    await source.SubscribeAsync(onNextAsync, () => default);\n}","preventionTips":["Never pass null for observer callbacks; use () => default for no-op completion.","Prefer the smaller overloads (source + onNext) instead of hand-rolling null handlers.","Validate delegate parameters at API boundaries before forwarding to SubscribeAsync.","Wrap handler selection logic so it always yields a fallback lambda."],"tags":["csharp","null-argument","asyncrx","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"}