dotnet/reactive · error · ArgumentNullException

scheduler

Error message

scheduler

What it means

SubscribeOn(source, scheduler) validates the scheduler after the source. Passing a null scheduler throws ArgumentNullException("scheduler") since the operator cannot schedule subscription/disposition work without one.

Solutions

  1. Pass a valid IAsyncScheduler instance, e.g. AsyncScheduler.DefaultScheduler.
  2. Fix the null source of the scheduler (DI registration, config).
  3. Verify you're not confusing the (source, scheduler) and (source, subscribeScheduler, disposeScheduler) overloads.

Example fix

// before
var obs = source.SubscribeOn(uiScheduler); // uiScheduler is null
// after
var obs = source.SubscribeOn(uiScheduler ?? AsyncScheduler.DefaultScheduler);
Defensive patterns

Strategy: validation

Validate before calling

if (scheduler == null)
    scheduler = AsyncScheduler.DefaultScheduler; // safe fallback before the call

Type guard

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

Try / catch

try
{
    var obs = source.SubscribeOn(scheduler);
}
catch (ArgumentNullException ex) when (ex.ParamName == "scheduler")
{
    logger.LogError(ex, "Null scheduler passed to SubscribeOn");
    obs = source.SubscribeOn(AsyncScheduler.DefaultScheduler);
}

Prevention

When it happens

Trigger: Calling source.SubscribeOn(null), or SubscribeOn(source, scheduler) where scheduler comes from an uninitialized field, failed DI resolution, or wrong positional argument.

Common situations: Scheduler injected via configuration not registered in DI; a custom scheduler factory returns null; argument-order swap when upgrading from a two- to three-parameter overload.

Related errors


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

Appendix: source

Thrown at AsyncRx.NET/System.Reactive.Async/Linq/Operators/SubscribeOn.cs:17

// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT License.
// See the LICENSE file in the project root for more information. 

using System.Reactive.Concurrency;
using System.Reactive.Disposables;

namespace System.Reactive.Linq
{
    public partial class AsyncObservable
    {
        public static IAsyncObservable<TSource> SubscribeOn<TSource>(this IAsyncObservable<TSource> source, IAsyncScheduler scheduler)
        {
            if (source == null)
                throw new ArgumentNullException(nameof(source));
            if (scheduler == null)
                throw new ArgumentNullException(nameof(scheduler));

            return SubscribeOn(source, scheduler, scheduler);
        }

        public static IAsyncObservable<TSource> SubscribeOn<TSource>(this IAsyncObservable<TSource> source, IAsyncScheduler subscribeScheduler, IAsyncScheduler disposeScheduler)
        {
            if (source == null)
                throw new ArgumentNullException(nameof(source));
            if (subscribeScheduler == null)
                throw new ArgumentNullException(nameof(subscribeScheduler));
            if (disposeScheduler == null)
                throw new ArgumentNullException(nameof(disposeScheduler));

            return CreateAsyncObservable<TSource>.From(
                source,
                (subscribeScheduler, disposeScheduler),
                static async (source, state, observer) =>
                {

View on GitHub (pinned to 94b5d5ab91)