dotnet/reactive · error · ArgumentNullException
Value cannot be null. (Parameter 'onError')
Error message
Value cannot be null. (Parameter 'onError')
What it means
Thrown by the two-action SubscribeAsync(source, onNext, onError) overload when the onError action is null. The library requires a non-null error handler so faults on the source do not become unhandled exceptions, and throws ArgumentNullException at subscribe time.
Solutions
- Pass a real error handler such as ex => Log(ex) or ex => { } if truly ignoring.
- Use the SubscribeAsync(source, onNext) overload, which installs a default error handler that faults the subscription.
- Ensure injected dependencies used as error handlers are non-null before subscribing.
Example fix
// before await source.SubscribeAsync(x => Render(x), null); // after await source.SubscribeAsync(x => Render(x), ex => Console.Error.WriteLine(ex));
Defensive patterns
Strategy: validation
Validate before calling
if (onError == null) throw new ArgumentNullException(nameof(onError)); await source.SubscribeAsync(onNext, onError);
Type guard
bool HasErrorHandler(Action<Exception> onError) => onError is not null;
Try / catch
try
{
await source.SubscribeAsync(onNext, onError);
}
catch (ArgumentNullException ex) when (ex.ParamName == "onError")
{
await source.SubscribeAsync(onNext, ex => Console.Error.WriteLine(ex));
} Prevention
- Always supply an error action; use the source+onNext overload to get a default faulting handler.
- Wire a logging fallback in shared subscription helpers so onError is never null.
- Ensure injected loggers/handlers are non-null in test and production compositions.
- Review subscription sites for all handler arguments before merging.
When it happens
Trigger: Calling SubscribeAsync(source, onNext, null), e.g. omitting error handling because the caller expects exceptions to propagate via the ValueTask await.
Common situations: Migration from callbacks APIs without error handlers, or code where the error logger is injected and can be null in tests.
Related errors
- Value cannot be null. (Parameter 'onCompletedAsync')
- Value cannot be null. (Parameter 'onNext')
- source
- ArgumentNullException(nameof(onError))
- ArgumentNullException(nameof(onCompleted))
AI-assisted analysis of dotnet/reactive@94b5d5ab91 (2026-09-15).
Data as JSON: /api/errors/a98863ff54f8f4ca.
Report an issue: GitHub.
Appendix: source
Thrown at AsyncRx.NET/System.Reactive.Async/AsyncObservableExtensions.cs:77
public static ValueTask<IAsyncDisposable> SubscribeAsync<T>(this IAsyncObservable<T> source, Action<T> onNext)
{
if (source == null)
throw new ArgumentNullException(nameof(source));
if (onNext == null)
throw new ArgumentNullException(nameof(onNext));
return source.SubscribeAsync(new AsyncObserver<T>(x => { onNext(x); return default; }, ex => new ValueTask(Task.FromException(ex)), () => default));
}
public static ValueTask<IAsyncDisposable> SubscribeAsync<T>(this IAsyncObservable<T> source, Action<T> onNext, Action<Exception> onError)
{
if (source == null)
throw new ArgumentNullException(nameof(source));
if (onNext == null)
throw new ArgumentNullException(nameof(onNext));
if (onError == null)
throw new ArgumentNullException(nameof(onError));
return source.SubscribeAsync(new AsyncObserver<T>(x => { onNext(x); return default; }, ex => { onError(ex); return default; }, () => default));
}
public static ValueTask<IAsyncDisposable> SubscribeAsync<T>(this IAsyncObservable<T> source, Action<T> onNext, Action onCompleted)
{
if (source == null)
throw new ArgumentNullException(nameof(source));
if (onNext == null)
throw new ArgumentNullException(nameof(onNext));
if (onCompleted == null)
throw new ArgumentNullException(nameof(onCompleted));
return source.SubscribeAsync(new AsyncObserver<T>(x => { onNext(x); return default; }, ex => new ValueTask(Task.FromException(ex)), () => { onCompleted(); return default; }));
}
public static ValueTask<IAsyncDisposable> SubscribeAsync<T>(this IAsyncObservable<T> source, Action<T> onNext, Action<Exception> onError, Action onCompleted)
{View on GitHub (pinned to 94b5d5ab91)