{"record":{"id":"3b35315e630d7f39","repo":"dotnet/reactive","slug":"value-cannot-be-null-parameter-error-unsafeasyncobserver","errorCode":null,"errorMessage":"Value cannot be null. (Parameter 'error')","messagePattern":"Value cannot be null\\. \\(Parameter 'error'\\)","errorType":"exception","errorClass":"ArgumentNullException","httpStatus":null,"severity":"error","filePath":"AsyncRx.NET/System.Reactive.Async/Internal/UnsafeAsyncObserver.cs","lineNumber":24,"sourceCode":"\nnamespace System.Reactive\n{\n    public class UnsafeAsyncObserver<T> : IAsyncObserver<T>\n    {\n        private readonly Func<T, ValueTask> _onNextAsync;\n        private readonly Func<Exception, ValueTask> _onErrorAsync;\n        private readonly Func<ValueTask> _onCompletedAsync;\n\n        public UnsafeAsyncObserver(Func<T, ValueTask> onNextAsync, Func<Exception, ValueTask> onErrorAsync, Func<ValueTask> onCompletedAsync)\n        {\n            _onNextAsync = onNextAsync ?? throw new ArgumentNullException(nameof(onNextAsync));\n            _onErrorAsync = onErrorAsync ?? throw new ArgumentNullException(nameof(onErrorAsync));\n            _onCompletedAsync = onCompletedAsync ?? throw new ArgumentNullException(nameof(onCompletedAsync));\n        }\n\n        public ValueTask OnCompletedAsync() => _onCompletedAsync();\n\n        public ValueTask OnErrorAsync(Exception error) => _onErrorAsync(error ?? throw new ArgumentNullException(nameof(error)));\n\n        public ValueTask OnNextAsync(T value) => _onNextAsync(value);\n    }\n}\n","sourceCodeStart":6,"sourceCodeEnd":29,"githubUrl":"https://github.com/dotnet/reactive/blob/94b5d5ab912789f5abe9a72138a25bbd716fe59c/AsyncRx.NET/System.Reactive.Async/Internal/UnsafeAsyncObserver.cs#L6-L29","documentation":"UnsafeAsyncObserver.OnErrorAsync guards its error parameter and throws ArgumentNullException when the Exception argument is null. Passing null to signal an error is not allowed; observers must always receive a concrete Exception instance describing the failure. This is a per-call guard on the delivery path, unlike the constructor guards at lines 15-17.","triggerScenarios":"Calling observer.OnErrorAsync(null) — e.g. forwarding an exception variable that was null, or a pipeline that synthesizes error notifications without an Exception instance.","commonSituations":"Bridging from another reactive/async library where errors can be signaled without an exception object; code paths where a caught exception was reassigned to null; logging middleware that nulls out the exception before forwarding.","solutions":["Always pass a real Exception, e.g. new InvalidOperationException(\"unknown failure\") when no better one exists","Audit code that forwards exceptions to OnErrorAsync and ensure the variable cannot be null at the call site","Wrap the forwarding call in a null check or use ex ?? new Exception(...) before calling"],"exampleFix":"// before\nawait observer.OnErrorAsync(lastException); // lastException may be null\n// after\nawait observer.OnErrorAsync(lastException ?? new InvalidOperationException(\"An error occurred with no exception details.\"));","handlingStrategy":"validation","validationCode":"if (error == null) error = new InvalidOperationException(\"Unspecified error\");","typeGuard":"static bool HasException(Exception ex) => ex != null;","tryCatchPattern":"try { await observer.OnErrorAsync(ex); } catch (ArgumentNullException) { await observer.OnErrorAsync(new InvalidOperationException(\"null error supplied\")); }","preventionTips":["Never signal errors with a null Exception; synthesize one if the cause is unknown","Null-coalesce at forwarding points: OnErrorAsync(ex ?? new Exception(...))","Avoid reassigning caught exception variables to null"],"tags":["argumentnull","asyncrx","observer","null-check"],"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"}