dotnet/reactive · error · ArgumentNullException

action

Error message

action

What it means

The scheduler-taking 15-argument ToAsync overload throws ArgumentNullException with parameter name 'action' when the delegate is null. When calling the two-parameter form, both 'action' and 'scheduler' are validated, and 'action' is checked first, so this error fires before the scheduler is even examined.

Solutions

  1. Supply a non-null Action<...> delegate as the first argument.
  2. Null-check the delegate before invoking ToAsync.
  3. If both may be null, fix the delegate first - the check order means the scheduler error would be masked.
  4. Substitute a default delegate when resolution fails.

Example fix

// before
Observable.ToAsync(null, Scheduler.Default);
// after
Observable.ToAsync(myAction, Scheduler.Default);
Defensive patterns

Strategy: validation

Validate before calling

if (action == null || scheduler == null) throw new ArgumentNullException(action == null ? nameof(action) : nameof(scheduler));

Type guard

bool ValidArgs(Action<...> a, IScheduler s) => a != null && s != null;

Try / catch

try { Observable.ToAsync(action, scheduler); } catch (ArgumentNullException ex) when (ex.ParamName == "action") { /* fix delegate */ }

Prevention

When it happens

Trigger: Calling Observable.ToAsync(action, scheduler) (15-arg Action overload) with a null delegate, regardless of whether the scheduler is valid.

Common situations: Same as the single-argument overload: dynamic delegate resolution returning null, uninitialized delegate fields, or method groups lost through conditional logic.

Related errors


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

Appendix: source

Thrown at Rx.NET/Source/src/System.Reactive/Linq/Observable.Async.cs:3519

        /// <typeparam name="TArg6">The type of the sixth argument passed to the action.</typeparam>
        /// <typeparam name="TArg7">The type of the seventh argument passed to the action.</typeparam>
        /// <typeparam name="TArg8">The type of the eighth argument passed to the action.</typeparam>
        /// <typeparam name="TArg9">The type of the ninth argument passed to the action.</typeparam>
        /// <typeparam name="TArg10">The type of the tenth argument passed to the action.</typeparam>
        /// <typeparam name="TArg11">The type of the eleventh argument passed to the action.</typeparam>
        /// <typeparam name="TArg12">The type of the twelfth argument passed to the action.</typeparam>
        /// <typeparam name="TArg13">The type of the thirteenth argument passed to the action.</typeparam>
        /// <typeparam name="TArg14">The type of the fourteenth argument passed to the action.</typeparam>
        /// <typeparam name="TArg15">The type of the fifteenth argument passed to the action.</typeparam>
        /// <param name="action">Action to convert to an asynchronous action.</param>
        /// <param name="scheduler">Scheduler to invoke the original action on.</param>
        /// <returns>Asynchronous action.</returns>
        /// <exception cref="ArgumentNullException"><paramref name="action"/> or <paramref name="scheduler"/> is null.</exception>
        public static Func<TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7, TArg8, TArg9, TArg10, TArg11, TArg12, TArg13, TArg14, TArg15, IObservable<Unit>> ToAsync<TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7, TArg8, TArg9, TArg10, TArg11, TArg12, TArg13, TArg14, TArg15>(this Action<TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7, TArg8, TArg9, TArg10, TArg11, TArg12, TArg13, TArg14, TArg15> action, IScheduler scheduler)
        {
            if (action == null)
            {
                throw new ArgumentNullException(nameof(action));
            }

            if (scheduler == null)
            {
                throw new ArgumentNullException(nameof(scheduler));
            }

            return s_impl.ToAsync(action, scheduler);
        }

        /// <summary>
        /// Converts the function into an asynchronous action. Each invocation of the resulting asynchronous action causes an invocation of the original synchronous action on the default scheduler.
        /// </summary>
        /// <typeparam name="TArg1">The type of the first argument passed to the action.</typeparam>
        /// <typeparam name="TArg2">The type of the second argument passed to the action.</typeparam>
        /// <typeparam name="TArg3">The type of the third argument passed to the action.</typeparam>
        /// <typeparam name="TArg4">The type of the fourth argument passed to the action.</typeparam>
        /// <typeparam name="TArg5">The type of the fifth argument passed to the action.</typeparam>

View on GitHub (pinned to 94b5d5ab91)