dotnet/reactive · error · ArgumentNullException
Argument cannot be null (Parameter name: onNext)
Error message
Argument cannot be null (Parameter name: onNext)
What it means
ForEachAsync(IAsyncObservable<TSource>, Action<TSource>, CancellationToken) throws ArgumentNullException because the onNext action is null. The synchronous-callback overload requires a non-null Action<TSource> that is invoked for every element; the argument is validated up front with the parameter name 'onNext'. A null action cannot be interpreted as 'do nothing' — use an empty lambda instead.
Solutions
- Pass a real handler, e.g. x => Console.WriteLine(x) or an empty x => { } when nothing needs doing.
- If the handler is optional, coalesce: onNext ?? (x => { }).
- Ensure the delegate field/property is assigned before the pipeline is started.
- Validate handler presence at configuration time and reject the pipeline early with a clear message.
Example fix
// before
Action<int> handler = _handlers.Get("onNext"); // may be null
await source.ForEachAsync(handler);
// after
await source.ForEachAsync(_handlers.Get("onNext") ?? (x => { })); Defensive patterns
Strategy: validation
Validate before calling
if (onNext == null)
onNext = _ => { }; // or throw with context
return source.ForEachAsync(onNext, token); Type guard
static bool IsNonNullHandler<T>(Action<T> h) => h is not null;
Try / catch
try { await source.ForEachAsync(onNext, token); }
catch (ArgumentNullException ex) when (ex.ParamName == "onNext") { /* attach default handler or report missing handler config */ } Prevention
- Use x => { } instead of null for 'do nothing' handlers.
- Coalesce optional handlers at the call site (onNext ?? (_ => { })).
- Assert handlers are wired before starting pipelines in integration tests.
When it happens
Trigger: Calling source.ForEachAsync((Action<TSource>)null) — passing an unassigned delegate field, a callback parameter that the caller omitted, or a conditional handler assignment that stayed null.
Common situations: Event-handler wiring where the handler is attached later; plugin architectures where the user-supplied handler is optional; unit tests passing null to check behavior.
Related errors
- Argument cannot be null (Parameter name: source)
- Value cannot be null. (Parameter 'scheduler')
- Value cannot be null. (Parameter 'source')
- Value cannot be null.
- Value cannot be null. (Parameter 'observer')
AI-assisted analysis of dotnet/reactive@94b5d5ab91 (2026-09-15).
Data as JSON: /api/errors/f1b007163755e08c.
Report an issue: GitHub.
Appendix: source
Thrown at AsyncRx.NET/System.Reactive.Async/Linq/Operators/ForEachAsync.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.Reactive.Disposables;
using System.Threading;
using System.Threading.Tasks;
namespace System.Reactive.Linq
{
public partial class AsyncObservable
{
public static Task ForEachAsync<TSource>(this IAsyncObservable<TSource> source, Action<TSource> onNext, CancellationToken token = default)
{
if (source == null)
throw new ArgumentNullException(nameof(source));
if (onNext == null)
throw new ArgumentNullException(nameof(onNext));
return ForEachAsyncCore(source, (x, i) => { onNext(x); return Task.CompletedTask; }, token);
}
public static Task ForEachAsync<TSource>(this IAsyncObservable<TSource> source, Func<TSource, Task> onNext, CancellationToken token = default)
{
if (source == null)
throw new ArgumentNullException(nameof(source));
if (onNext == null)
throw new ArgumentNullException(nameof(onNext));
return ForEachAsyncCore(source, (x, i) => onNext(x), token);
}
public static Task ForEachAsync<TSource>(this IAsyncObservable<TSource> source, Action<TSource, int> onNext, CancellationToken token = default)
{
if (source == null)
throw new ArgumentNullException(nameof(source));View on GitHub (pinned to 94b5d5ab91)