dotnet/reactive · error · ArgumentNullException

Value cannot be null. (Parameter 'onError')

Error message

Value cannot be null. (Parameter 'onError')

What it means

ArgumentNullException thrown by the three-handler Do<TSource> extension when the onError expression (Expression<Func<Exception, Task>>) is null. The error handler is part of the provider expression tree, so it must be non-null and is validated after onNext. The message names 'onError'.

Solutions

  1. Pass a no-op error handler: _ => Task.CompletedTask
  2. Use a Do overload that omits onError when error handling is not required
  3. Make the handler registry fall back to a default error expression
  4. Guard configuration-driven wiring so a missing handler never yields null

Example fix

// before
query.Do(OnNext, cfg.OnErrorHandler /* null when disabled */, OnDone);
// after
query.Do(OnNext, cfg.OnErrorHandler ?? (_ => Task.CompletedTask), OnDone);
Defensive patterns

Strategy: validation

Validate before calling

if (onError is null) onError = _ => Task.CompletedTask;

Type guard

static bool HasError(Expression<Func<Exception, Task>>? h) => h is not null;

Try / catch

try { q = source.Do(onNext, onError, onCompleted); }
catch (ArgumentNullException ex) when (ex.ParamName == "onError") { q = source.Do(onNext, _ => Task.CompletedTask, onCompleted); }

Prevention

When it happens

Trigger: Calling Do(source, onNext, null, onCompleted) — typically when error handling was optional in the caller's design or a handler-resolution step returned null for onError.

Common situations: Query pipelines where error logging is disabled by configuration; abstracted handler registries missing an entry for the error slot; copy-pasted Do calls with one argument deleted.

Related errors


AI-assisted analysis of dotnet/reactive@94b5d5ab91 (2026-09-15). Data as JSON: /api/errors/14f8b63fa959a23f. Report an issue: GitHub.

Appendix: source

Thrown at Ix.NET/Source/System.Interactive.Async.Providers/System/Linq/AsyncQueryableEx.Generated.cs:1078

                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));
            if (onCompleted == null)
                throw new ArgumentNullException(nameof(onCompleted));

            return source.Provider.CreateQuery<TSource>(Expression.Call(Do__TSource__4__2(typeof(TSource)), source.Expression, onNext, onError, onCompleted));
        }

        private static MethodInfo? s_Expand__TSource__2__0;
        
        private static MethodInfo Expand__TSource__2__0(Type TSource) =>
            (s_Expand__TSource__2__0 ??
            (s_Expand__TSource__2__0 = new Func<IAsyncQueryable<object>, Expression<Func<object, CancellationToken, ValueTask<IAsyncEnumerable<object>>>>, IAsyncQueryable<object>>(Expand<object>).GetMethodInfo()!.GetGenericMethodDefinition())).MakeGenericMethod(TSource);

        public static IAsyncQueryable<TSource> Expand<TSource>(this IAsyncQueryable<TSource> source, Expression<Func<TSource, CancellationToken, ValueTask<IAsyncEnumerable<TSource>>>> selector)
        {
            if (source == null)
                throw new ArgumentNullException(nameof(source));
            if (selector == null)
                throw new ArgumentNullException(nameof(selector));

View on GitHub (pinned to 94b5d5ab91)