dotnet/reactive · error · ArgumentNullException
scheduler (Value cannot be null)
Error message
scheduler (Value cannot be null)
What it means
SchedulePeriodic<TState>(IScheduler, TState, TimeSpan, Func<TState,TState>) in Scheduler.Services.Emulation.cs throws ArgumentNullException when the IScheduler is null. The extension method needs a scheduler instance to run the periodic loop on; a null receiver cannot be dispatched. Rx validates this eagerly rather than failing when the periodic timer starts.
Solutions
- Pass a concrete scheduler such as Scheduler.Default, Scheduler.ThreadPool, or a test scheduler (TestScheduler) instead of null
- If the scheduler is resolved from DI/config, ensure the binding exists and check for null before calling
- Guard the call site: if (scheduler is null) throw new ArgumentNullException(nameof(scheduler)); with a clearer message
Example fix
// before IScheduler scheduler = config.GetScheduler(); // returns null scheduler.SchedulePeriodic(state, TimeSpan.FromSeconds(1), s => s); // after IScheduler scheduler = config.GetScheduler() ?? Scheduler.Default; scheduler.SchedulePeriodic(state, TimeSpan.FromSeconds(1), s => s);
Defensive patterns
Strategy: validation
Validate before calling
if (scheduler is null) throw new ArgumentNullException(nameof(scheduler)); if (period < TimeSpan.Zero) throw new ArgumentOutOfRangeException(nameof(period)); if (action is null) throw new ArgumentNullException(nameof(action)); scheduler.SchedulePeriodic(state, period, action);
Type guard
bool CanSchedulePeriodic(IScheduler s) => s is not null;
Try / catch
try { scheduler.SchedulePeriodic(state, period, action); }
catch (ArgumentNullException ex) when (ex.ParamName == "scheduler") { scheduler = Scheduler.Default; /* retry */ } Prevention
- Resolve IScheduler through DI with Scheduler.Default as fallback binding
- Avoid nullable IScheduler fields; use Lazy<IScheduler> or static readonly
- In tests always construct a TestScheduler instead of passing null stubs
When it happens
Trigger: Invoking scheduler.SchedulePeriodic(state, period, action) with a null scheduler reference, e.g. IScheduler s = null; s.SchedulePeriodic(state, TimeSpan.FromSeconds(1), x => x), or passing a scheduler factory/property that returned null.
Common situations: Injecting IScheduler via DI where no binding is registered (null default), a configuration-selected scheduler that fell back to null, calling through a wrapper class whose scheduler field was never initialized, or code moved off DefaultScheduler during a refactor.
Related errors
- scheduler
- threadFactory (Parameter 'threadFactory')
- action (Parameter 'action')
- comparer (Parameter 'comparer')
- scheduler (Parameter 'scheduler')
AI-assisted analysis of dotnet/reactive@94b5d5ab91 (2026-09-15).
Data as JSON: /api/errors/e923807f9a6ef7f7.
Report an issue: GitHub.
Appendix: source
Thrown at Rx.NET/Source/src/System.Reactive/Concurrency/Scheduler.Services.Emulation.cs:32
/// <summary>
/// Schedules a periodic piece of work by dynamically discovering the scheduler's capabilities.
/// If the scheduler supports periodic scheduling, the request will be forwarded to the periodic scheduling implementation.
/// If the scheduler provides stopwatch functionality, the periodic task will be emulated using recursive scheduling with a stopwatch to correct for time slippage.
/// Otherwise, the periodic task will be emulated using recursive scheduling.
/// </summary>
/// <typeparam name="TState">The type of the state passed to the scheduled action.</typeparam>
/// <param name="scheduler">The scheduler to run periodic work on.</param>
/// <param name="state">Initial state passed to the action upon the first iteration.</param>
/// <param name="period">Period for running the work periodically.</param>
/// <param name="action">Action to be executed, potentially updating the state.</param>
/// <returns>The disposable object used to cancel the scheduled recurring action (best effort).</returns>
/// <exception cref="ArgumentNullException"><paramref name="scheduler"/> or <paramref name="action"/> is <c>null</c>.</exception>
/// <exception cref="ArgumentOutOfRangeException"><paramref name="period"/> is less than <see cref="TimeSpan.Zero"/>.</exception>
public static IDisposable SchedulePeriodic<TState>(this IScheduler scheduler, TState state, TimeSpan period, Func<TState, TState> action)
{
if (scheduler == null)
{
throw new ArgumentNullException(nameof(scheduler));
}
if (period < TimeSpan.Zero)
{
throw new ArgumentOutOfRangeException(nameof(period));
}
if (action == null)
{
throw new ArgumentNullException(nameof(action));
}
return SchedulePeriodic_(scheduler, state, period, action);
}
/// <summary>
/// Schedules a periodic piece of work by dynamically discovering the scheduler's capabilities.
/// If the scheduler supports periodic scheduling, the request will be forwarded to the periodic scheduling implementation.View on GitHub (pinned to 94b5d5ab91)