dotnet/reactive · error · ArgumentNullException
Value cannot be null. (Parameter 'onCompleted')
Error message
Value cannot be null. (Parameter 'onCompleted')
What it means
ArgumentNullException thrown by the AsyncQueryableEx.Do<TSource> overload taking onNext/onError/onCompleted handlers when the onCompleted expression is null. Do builds a query operator whose three handler arguments are translated into the provider expression tree, so each must be non-null and is validated in order. The message names 'onCompleted'.
Solutions
- Pass a no-op completion expression: () => Task.CompletedTask
- If only onNext is needed, use the single-handler Do overload instead
- Fix handler-factory code so it emits a completed-task lambda rather than null for onCompleted
- Wrap observer adaptation to always materialize all three handlers
Example fix
// before query.Do(x => Log(x), e => LogErr(e), null); // after query.Do(x => Log(x), e => LogErr(e), () => Task.CompletedTask);
Defensive patterns
Strategy: validation
Validate before calling
if (onCompleted is null) onCompleted = () => Task.CompletedTask;
Type guard
static bool HasCompleted(Expression<Func<Task>>? h) => h is not null;
Try / catch
try { q = source.Do(onNext, onError, onCompleted); }
catch (ArgumentNullException ex) when (ex.ParamName == "onCompleted") { q = source.Do(onNext, onError, () => Task.CompletedTask); } Prevention
- Treat all three Do handlers as required; use () => Task.CompletedTask for no-ops
- Use the smaller Do overloads when fewer handlers are needed
- Coalesce optional handlers with ?? before calling Do
When it happens
Trigger: Calling Do(source, onNext, onError, null) — typically because source/onNext/onError were validated earlier and only onCompleted was left null, e.g. a partial-handler factory that supplies only some callbacks.
Common situations: Logging/tap pipelines where the completion handler was deemed optional; adapters mapping Rx-style observers to queryable Do with a missing onCompleted; code generators emitting null for empty handlers.
Related errors
- Value cannot be null. (Parameter 'onNext')
- Value cannot be null. (Parameter 'onError')
- Value cannot be null. (Parameter 'selector')
- Value cannot be null. (Parameter 'onCompletedAsync')
- Value cannot be null. (Parameter 'onNext')
AI-assisted analysis of dotnet/reactive@94b5d5ab91 (2026-09-15).
Data as JSON: /api/errors/79c35d5ddd836088.
Report an issue: GitHub.
Appendix: source
Thrown at Ix.NET/Source/System.Interactive.Async.Providers/System/Linq/AsyncQueryableEx.Generated.cs:1060
return source.Provider.CreateQuery<TSource>(Expression.Call(Do__TSource__4__0(typeof(TSource)), source.Expression, onNext, onError, Expression.Constant(onCompleted, typeof(Action))));
}
private static MethodInfo? s_Do__TSource__4__1;
private static MethodInfo Do__TSource__4__1(Type TSource) =>
(s_Do__TSource__4__1 ??
(s_Do__TSource__4__1 = new Func<IAsyncQueryable<object>, Expression<Func<object, CancellationToken, Task>>, Expression<Func<Exception, CancellationToken, Task>>, Expression<Func<CancellationToken, Task>>, IAsyncQueryable<object>>(Do<object>).GetMethodInfo()!.GetGenericMethodDefinition())).MakeGenericMethod(TSource);
public static IAsyncQueryable<TSource> Do<TSource>(this IAsyncQueryable<TSource> source, Expression<Func<TSource, CancellationToken, Task>> onNext, Expression<Func<Exception, CancellationToken, Task>> onError, Expression<Func<CancellationToken, Task>> onCompleted)
{
if (source == null)
throw new ArgumentNullException(nameof(source));
if (onNext == null)
throw new ArgumentNullException(nameof(onNext));
if (onError == null)
throw new ArgumentNullException(nameof(onError));
if (onCompleted == null)
throw new ArgumentNullException(nameof(onCompleted));
return source.Provider.CreateQuery<TSource>(Expression.Call(Do__TSource__4__1(typeof(TSource)), source.Expression, onNext, onError, onCompleted));
}
private static MethodInfo? s_Do__TSource__4__2;
private static MethodInfo Do__TSource__4__2(Type TSource) =>
(s_Do__TSource__4__2 ??
(s_Do__TSource__4__2 = new Func<IAsyncQueryable<object>, Expression<Func<object, Task>>, Expression<Func<Exception, Task>>, Expression<Func<Task>>, IAsyncQueryable<object>>(Do<object>).GetMethodInfo()!.GetGenericMethodDefinition())).MakeGenericMethod(TSource);
public static IAsyncQueryable<TSource> Do<TSource>(this IAsyncQueryable<TSource> source, Expression<Func<TSource, Task>> onNext, Expression<Func<Exception, Task>> onError, Expression<Func<Task>> onCompleted)
{
if (source == null)
throw new ArgumentNullException(nameof(source));
if (onNext == null)
throw new ArgumentNullException(nameof(onNext));
if (onError == null)
throw new ArgumentNullException(nameof(onError));View on GitHub (pinned to 94b5d5ab91)