dotnet/reactive · error · ArgumentNullException
Value cannot be null. (Parameter 'onErrorAsync')
Error message
Value cannot be null. (Parameter 'onErrorAsync')
What it means
UnsafeAsyncObserver's constructor validates all three delegate arguments and throws ArgumentNullException when onErrorAsync is null. The library requires an explicit error-handling delegate so every observer has a well-defined OnErrorAsync path; there is no default no-op handler for this unsafe/fast-path type. This is an eager, fail-fast guard thrown at construction time, not during event delivery.
Solutions
- Pass a non-null error handler delegate, e.g. ex => ValueTask.CompletedTask or one that logs the exception
- Check every UnsafeAsyncObserver construction site and supply all three delegates (onNextAsync, onErrorAsync, onCompletedAsync)
- Wrap construction in a helper factory with default delegates so callers can omit error handling explicitly
Example fix
// before
var observer = new UnsafeAsyncObserver<int>(
x => ValueTask.CompletedTask,
null,
() => ValueTask.CompletedTask);
// after
var observer = new UnsafeAsyncObserver<int>(
x => ValueTask.CompletedTask,
ex => Console.Error.WriteLine(ex),
() => ValueTask.CompletedTask); Defensive patterns
Strategy: validation
Validate before calling
if (onErrorAsync == null) throw new ArgumentException("onErrorAsync delegate is required"); Type guard
static bool IsValidObserver<T>(Func<T, ValueTask> n, Func<Exception, ValueTask> e, Func<ValueTask> c) => n != null && e != null && c != null;
Try / catch
try { var obs = new UnsafeAsyncObserver<int>(onNext, onError, onCompleted); } catch (ArgumentNullException ex) { /* ex.ParamName == "onErrorAsync" */ } Prevention
- Always supply all three delegates when constructing UnsafeAsyncObserver
- Use named lambdas or methods so intent per delegate is clear
- Never pass optional/conditional delegates; use no-op lambdas like () => ValueTask.CompletedTask
When it happens
Trigger: Calling new UnsafeAsyncObserver<T>(onNextAsync, null, onCompletedAsync) — i.e. passing a null Func<Exception, ValueTask> as the second constructor argument.
Common situations: Writing a custom subscription that handles OnNext and OnCompleted but forgets the error callback; refactoring code that previously swallowed exceptions; mapping from an observer abstraction with optional error handling onto this API that requires all three delegates.
Related errors
- Value cannot be null. (Parameter 'onCompletedAsync')
- Value cannot be null. (Parameter 'error')
- ArgumentNullException
- source
- observer
AI-assisted analysis of dotnet/reactive@94b5d5ab91 (2026-09-15).
Data as JSON: /api/errors/7f28e4fc62a78e5f.
Report an issue: GitHub.
Appendix: source
Thrown at AsyncRx.NET/System.Reactive.Async/Internal/UnsafeAsyncObserver.cs:18
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT License.
// See the LICENSE file in the project root for more information.
using System.Threading.Tasks;
namespace System.Reactive
{
public class UnsafeAsyncObserver<T> : IAsyncObserver<T>
{
private readonly Func<T, ValueTask> _onNextAsync;
private readonly Func<Exception, ValueTask> _onErrorAsync;
private readonly Func<ValueTask> _onCompletedAsync;
public UnsafeAsyncObserver(Func<T, ValueTask> onNextAsync, Func<Exception, ValueTask> onErrorAsync, Func<ValueTask> onCompletedAsync)
{
_onNextAsync = onNextAsync ?? throw new ArgumentNullException(nameof(onNextAsync));
_onErrorAsync = onErrorAsync ?? throw new ArgumentNullException(nameof(onErrorAsync));
_onCompletedAsync = onCompletedAsync ?? throw new ArgumentNullException(nameof(onCompletedAsync));
}
public ValueTask OnCompletedAsync() => _onCompletedAsync();
public ValueTask OnErrorAsync(Exception error) => _onErrorAsync(error ?? throw new ArgumentNullException(nameof(error)));
public ValueTask OnNextAsync(T value) => _onNextAsync(value);
}
}
View on GitHub (pinned to 94b5d5ab91)