dotnet/reactive · error · ArgumentNullException

scheduler

Error message

scheduler

What it means

Qbservable.ToQbservable(IQueryable<TSource>, IScheduler) throws ArgumentNullException when the scheduler argument is null. The scheduler is encoded into the query expression to control when evaluation runs, so a null IScheduler cannot be represented and is rejected up front.

Solutions

  1. Pass a concrete scheduler such as Scheduler.Default, Scheduler.CurrentThread, or a TestScheduler in tests.
  2. If the scheduler is configurable, default it: scheduler ?? Scheduler.Default (applied before the call).
  3. Fix the factory/DI registration so the IScheduler binding never resolves to null.

Example fix

// before
var q = query.ToQbservable(null);
// after
var q = query.ToQbservable(Scheduler.Default);
Defensive patterns

Strategy: validation

Validate before calling

if (scheduler is null) throw new InvalidOperationException("An IScheduler is required for ToQbservable(scheduler).");

Try / catch

try { var q = query.ToQbservable(scheduler); }
catch (ArgumentNullException ex) when (ex.ParamName == "scheduler") { /* fall back to Scheduler.Default or report config issue */ }

Prevention

When it happens

Trigger: Calling source.ToQbservable(null); passing a scheduler field/property that was never initialized; a scheduler factory or DI registration returning null (e.g. missing Scheduler.Default assignment).

Common situations: Configuration-driven scheduler selection where a config key maps to no scheduler; unit tests substituting null for Scheduler.Default/TestScheduler; refactors removing scheduler initialization.

Related errors


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

Appendix: source

Thrown at Rx.NET/Source/src/System.Reactive/Linq/Qbservable.cs:78

        /// <summary>
        /// Converts an enumerable sequence to an observable sequence, using the specified scheduler to run the enumeration loop.
        /// </summary>
        /// <typeparam name="TSource">The type of the elements in the source sequence.</typeparam>
        /// <param name="source">Enumerable sequence to convert to an observable sequence.</param>
        /// <param name="scheduler">Scheduler to run the enumeration of the input sequence on.</param>
        /// <returns>The observable sequence whose elements are pulled from the given enumerable sequence.</returns>
        /// <exception cref="ArgumentNullException"><paramref name="source"/> or <paramref name="scheduler"/> is null.</exception>
        /// <remarks>This operator requires the source's <see cref="IQueryProvider"/> object (see <see cref="IQueryable.Provider"/>) to implement <see cref="IQbservableProvider"/>.</remarks>
        public static IQbservable<TSource> ToQbservable<TSource>(this IQueryable<TSource> source, IScheduler scheduler)
        {
            if (source == null)
            {
                throw new ArgumentNullException(nameof(source));
            }

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

            return ((IQbservableProvider)source.Provider).CreateQuery<TSource>(
                Expression.Call(
                    null,
                    new Func<IQueryable<TSource>, IScheduler, IQbservable <TSource>>(ToQbservable).Method,
                    source.Expression,
                    Expression.Constant(scheduler)
                )
            );
        }

        internal static Expression GetSourceExpression<TSource>(IObservable<TSource> source)
        {
            if (source is IQbservable<TSource> q)
            {
                return q.Expression;
            }

View on GitHub (pinned to 94b5d5ab91)