dotnet/reactive · error · ArgumentNullException

Value cannot be null. (Parameter 'scheduler')

Error message

Value cannot be null. (Parameter 'scheduler')

What it means

AsyncObservable.Range(start, count, scheduler) requires an explicit IAsyncScheduler to schedule the emission of values. Passing null throws ArgumentNullException naming 'scheduler'. The library does not fall back to a default scheduler on this overload, so the caller must supply one (e.g. TaskPoolAsyncScheduler.Default).

Solutions

  1. Pass a concrete scheduler such as TaskPoolAsyncScheduler.Default or NewThreadAsyncScheduler.Default.
  2. If you don't need scheduler control, call the two-argument Range(start, count) overload instead.
  3. Check why the scheduler variable is null (unregistered DI binding, failed config lookup) and fix the source.
  4. Guard/require a non-null scheduler in your own wrapper API so the failure is caught earlier with a clear message.

Example fix

// before
var xs = AsyncObservable.Range(0, 10, GetScheduler()); // GetScheduler() returned null
// after
var sched = GetScheduler() ?? TaskPoolAsyncScheduler.Default;
var xs = AsyncObservable.Range(0, 10, sched);
Defensive patterns

Strategy: validation

Validate before calling

if (scheduler == null) scheduler = TaskPoolAsyncScheduler.Default; // or throw with a clear message

Type guard

static bool HasScheduler(IAsyncScheduler s) => s is not null;

Try / catch

try { var xs = AsyncObservable.Range(start, count, scheduler); }
catch (ArgumentNullException ex) when (ex.ParamName == "scheduler") { /* supply fallback scheduler or report config error */ }

Prevention

When it happens

Trigger: Calling AsyncObservable.Range(start, count, null) — typically when the scheduler is obtained from configuration, dependency injection, or a factory that returned null.

Common situations: DI container without a registered IAsyncScheduler; a config-driven scheduler lookup returning null; a helper method forwarding an optional scheduler parameter that defaulted to null; using this overload when the scheduler-less overload Range(start, count) was intended (it defaults to TaskPoolAsyncScheduler.Default).

Related errors


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

Appendix: source

Thrown at AsyncRx.NET/System.Reactive.Async/Linq/Operators/Range.cs:25

namespace System.Reactive.Linq
{
    public partial class AsyncObservable
    {
        public static IAsyncObservable<int> Range(int start, int count)
        {
            if (count < 0 || ((long)start) + count - 1 > int.MaxValue)
                throw new ArgumentOutOfRangeException(nameof(count));

            return Create<int>(observer => AsyncObserver.Range(observer, start, count));
        }

        public static IAsyncObservable<int> Range(int start, int count, IAsyncScheduler scheduler)
        {
            if (count < 0 || ((long)start) + count - 1 > int.MaxValue)
                throw new ArgumentOutOfRangeException(nameof(count));
            if (scheduler == null)
                throw new ArgumentNullException(nameof(scheduler));

            return Create<int>(observer => AsyncObserver.Range(observer, start, count, scheduler));
        }
    }

    public partial class AsyncObserver
    {
        public static ValueTask<IAsyncDisposable> Range(IAsyncObserver<int> observer, int start, int count) => Range(observer, start, count, TaskPoolAsyncScheduler.Default);

        public static ValueTask<IAsyncDisposable> Range(IAsyncObserver<int> observer, int start, int count, IAsyncScheduler scheduler)
        {
            if (observer == null)
                throw new ArgumentNullException(nameof(observer));
            if (count < 0 || ((long)start) + count - 1 > int.MaxValue)
                throw new ArgumentOutOfRangeException(nameof(count));
            if (scheduler == null)
                throw new ArgumentNullException(nameof(scheduler));

View on GitHub (pinned to 94b5d5ab91)