dotnet/reactive · error · ArgumentNullException
nameof(scheduler)
Error message
nameof(scheduler)
What it means
System.ArgumentNullException thrown by Observable.ObserveOn<TSource>(IObservable<TSource>, IScheduler) when the scheduler argument is null. The public wrapper validates both parameters before delegating to s_impl.ObserveOn, so a null IScheduler is rejected up front rather than failing later inside the operator.
Solutions
- Pass a concrete IScheduler, e.g. System.Reactive.Concurrency Scheduler.Default, ThreadPoolScheduler.Instance, or EventLoopScheduler.
- Check the variable supplying the scheduler for null before calling ObserveOn and fix its initialization or DI registration.
- If the scheduler is optional, guard with 'scheduler ?? Scheduler.Default' instead of passing null.
Example fix
// before var sched = config.Scheduler; // may be null source.ObserveOn(sched); // after var sched = config.Scheduler ?? Scheduler.Default; source.ObserveOn(sched);
Defensive patterns
Strategy: validation
Validate before calling
if (scheduler is null) throw new InvalidOperationException("scheduler must be set before calling ObserveOn");
source.ObserveOn(scheduler); Type guard
bool HasScheduler(IScheduler s) => s is not null;
Try / catch
try { obs = source.ObserveOn(scheduler); }
catch (ArgumentNullException ex) when (ex.ParamName == "scheduler") { obs = source.ObserveOn(Scheduler.Default); } Prevention
- Never pass a scheduler obtained from a nullable lookup without a ?? fallback to Scheduler.Default.
- Prefer concrete static schedulers (Scheduler.Default, TaskPoolScheduler.Default) over nullable fields.
- Keep IScheduler DI registrations mandatory so resolution fails fast instead of injecting null.
When it happens
Trigger: Calling source.ObserveOn(scheduler) with scheduler == null, e.g.ObserveOn(Schedulers.Default) typed as a variable that was never assigned, or passing the result of a lookup/factory that returned null.
Common situations: Resolving an IScheduler from DI/config where the registration is missing; a scheduler field initialized after first use; refactoring away from scheduler properties (ThreadPool/TaskPool/NewThread) and leaving a null placeholder.
Related errors
- Value cannot be null. (Parameter 'iterate')
- Value cannot be null. (Parameter 'resultSelector')
- Value cannot be null. (Parameter 'scheduler')
- scheduler
- Value cannot be null. (Parameter 'action')
AI-assisted analysis of dotnet/reactive@94b5d5ab91 (2026-09-15).
Data as JSON: /api/errors/19c9e27d94e1a118.
Report an issue: GitHub.
Appendix: source
Thrown at Rx.NET/Source/src/System.Reactive/Linq/Observable.Concurrency.cs:35
/// <typeparam name="TSource">The type of the elements in the source sequence.</typeparam>
/// <param name="source">Source sequence.</param>
/// <param name="scheduler">Scheduler to notify observers on.</param>
/// <returns>The source sequence whose observations happen on the specified scheduler.</returns>
/// <exception cref="ArgumentNullException"><paramref name="source"/> or <paramref name="scheduler"/> is null.</exception>
/// <remarks>
/// This only invokes observer callbacks on a scheduler. In case the subscription and/or unsubscription actions have side-effects
/// that require to be run on a scheduler, use <see cref="Observable.SubscribeOn{TSource}(IObservable{TSource}, IScheduler)"/>.
/// </remarks>
public static IObservable<TSource> ObserveOn<TSource>(this IObservable<TSource> source, IScheduler scheduler)
{
if (source == null)
{
throw new ArgumentNullException(nameof(source));
}
if (scheduler == null)
{
throw new ArgumentNullException(nameof(scheduler));
}
return s_impl.ObserveOn(source, scheduler);
}
/// <summary>
/// Wraps the source sequence in order to run its observer callbacks on the specified synchronization context.
/// </summary>
/// <typeparam name="TSource">The type of the elements in the source sequence.</typeparam>
/// <param name="source">Source sequence.</param>
/// <param name="context">Synchronization context to notify observers on.</param>
/// <returns>The source sequence whose observations happen on the specified synchronization context.</returns>
/// <exception cref="ArgumentNullException"><paramref name="source"/> or <paramref name="context"/> is null.</exception>
/// <remarks>
/// This only invokes observer callbacks on a synchronization context. In case the subscription and/or unsubscription actions have side-effects
/// that require to be run on a synchronization context, use <see cref="Observable.SubscribeOn{TSource}(IObservable{TSource}, SynchronizationContext)"/>.
/// </remarks>
public static IObservable<TSource> ObserveOn<TSource>(this IObservable<TSource> source, SynchronizationContext context)View on GitHub (pinned to 94b5d5ab91)