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

  1. Pass a concrete IScheduler, e.g. System.Reactive.Concurrency Scheduler.Default, ThreadPoolScheduler.Instance, or EventLoopScheduler.
  2. Check the variable supplying the scheduler for null before calling ObserveOn and fix its initialization or DI registration.
  3. 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

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


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)