dotnet/reactive · error · ArgumentNullException

scheduler

Error message

scheduler

What it means

The 15-argument ToAsync overload with a scheduler throws ArgumentNullException with parameter name 'scheduler' when the IScheduler argument is null. The action check has already passed at this point; Rx requires a concrete scheduler to dispatch the asynchronous action invocation.

Solutions

  1. Pass Scheduler.Default, Scheduler.TaskPool, Scheduler.ThreadPool, or a custom IScheduler.
  2. Fix the null source of the scheduler (DI registration, config, factory).
  3. Use the single-argument ToAsync overload if default scheduling suffices.
  4. Coalesce: scheduler ?? Scheduler.Default.

Example fix

// before
Observable.ToAsync(action, configuredScheduler); // configuredScheduler is null
// after
Observable.ToAsync(action, configuredScheduler ?? Scheduler.Default);
Defensive patterns

Strategy: validation

Validate before calling

if (scheduler == null) throw new ArgumentNullException(nameof(scheduler)); // or scheduler ??= Scheduler.Default;

Type guard

bool HasScheduler(IScheduler s) => s != null;

Try / catch

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

Prevention

When it happens

Trigger: Calling Observable.ToAsync(action, (IScheduler)null) with a valid action but a null scheduler reference.

Common situations: Uninitialized scheduler fields; DI or configuration not providing a scheduler; passing the result of a GetScheduler() method that returned null; test code forgetting to wire a TestScheduler.

Related errors


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

Appendix: source

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

        /// <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>
        /// <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>

View on GitHub (pinned to 94b5d5ab91)