dotnet/reactive · error · ArgumentNullException

scheduler (Value cannot be null)

Error message

scheduler (Value cannot be null)

What it means

System.Reactive's ScheduleAsync extension requires a non-null IScheduler receiver. Passing null causes an ArgumentNullException with message "Value cannot be null (Parameter 'scheduler')". The library validates up front so no scheduling machinery is initialized for an invalid call.

Solutions

  1. Use a concrete scheduler instance such as Scheduler.Default, TaskPoolScheduler.Default, or NewThreadScheduler.Default.
  2. Null-check the scheduler before calling and substitute Scheduler.Default when absent.
  3. Correct the DI registration or factory that yields the null scheduler.

Example fix

// before
IScheduler scheduler = null;
scheduler.ScheduleAsync(state, dueTime, action); // throws
// after
var scheduler = Scheduler.Default;
scheduler.ScheduleAsync(state, dueTime, action);
Defensive patterns

Strategy: validation

Validate before calling

if (scheduler == null) scheduler = Scheduler.Default;

Type guard

bool HasScheduler(IScheduler s) => s is not null;

Try / catch

try { disposable = scheduler.ScheduleAsync(state, dueTime, action); }
catch (ArgumentNullException ex) when (ex.ParamName == "scheduler") { disposable = Scheduler.Default.ScheduleAsync(state, dueTime, action); }

Prevention

When it happens

Trigger: Calling scheduler.ScheduleAsync<TState>(state, dueTime, Func<IScheduler, TState, CancellationToken, Task<IDisposable>> action) on a null IScheduler receiver — legal syntax because it is a C# extension method.

Common situations: DI-resolved scheduler was not registered and injected as null; a custom scheduler factory returned null; scheduler variable captured before initialization.

Related errors


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

Appendix: source

Thrown at Rx.NET/Source/src/System.Reactive/Concurrency/Scheduler.Async.cs:381

            return ScheduleAsync_(scheduler, state, dueTime, action);
        }

        /// <summary>
        /// Schedules work using an asynchronous method, allowing for cooperative scheduling in an imperative coding style.
        /// </summary>
        /// <typeparam name="TState">The type of the state passed to the scheduled action.</typeparam>
        /// <param name="scheduler">Scheduler to schedule work on.</param>
        /// <param name="state">State to pass to the asynchronous method.</param>
        /// <param name="dueTime">Absolute time at which to execute the action.</param>
        /// <param name="action">Asynchronous method to run the work, using Yield and Sleep operations for cooperative scheduling and injection of cancellation points.</param>
        /// <returns>Disposable object that allows to cancel outstanding work on cooperative cancellation points or through the cancellation token passed to the asynchronous method.</returns>
        /// <exception cref="ArgumentNullException"><paramref name="scheduler"/> or <paramref name="action"/> is <c>null</c>.</exception>
        public static IDisposable ScheduleAsync<TState>(this IScheduler scheduler, TState state, DateTimeOffset dueTime, Func<IScheduler, TState, CancellationToken, Task<IDisposable>> action)
        {
            if (scheduler == null)
            {
                throw new ArgumentNullException(nameof(scheduler));
            }

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

            return ScheduleAsync_(scheduler, state, dueTime, action);
        }

        /// <summary>
        /// Schedules work using an asynchronous method, allowing for cooperative scheduling in an imperative coding style.
        /// </summary>
        /// <param name="scheduler">Scheduler to schedule work on.</param>
        /// <param name="dueTime">Absolute time at which to execute the action.</param>
        /// <param name="action">Asynchronous method to run the work, using Yield and Sleep operations for cooperative scheduling and injection of cancellation points.</param>
        /// <returns>Disposable object that allows to cancel outstanding work on cooperative cancellation points or through the cancellation token passed to the asynchronous method.</returns>
        /// <exception cref="ArgumentNullException"><paramref name="scheduler"/> or <paramref name="action"/> is <c>null</c>.</exception>

View on GitHub (pinned to 94b5d5ab91)