dotnet/reactive · error · ArgumentNullException

subscribeScheduler

Error message

subscribeScheduler

What it means

SubscribeOn(source, subscribeScheduler, disposeScheduler) validates each scheduler. Passing a null subscribeScheduler throws ArgumentNullException("subscribeScheduler") because subscription must be dispatched onto it.

Solutions

  1. Pass a concrete subscribe scheduler, or call the single-scheduler overload SubscribeOn(source, scheduler) which uses the same scheduler for both.
  2. Fix the null initialization of the scheduler variable.
  3. Validate both schedulers before calling (see validation pattern).

Example fix

// before
var obs = source.SubscribeOn(null, disposeScheduler);
// after
var obs = source.SubscribeOn(subscribeScheduler ?? AsyncScheduler.DefaultScheduler, disposeScheduler);
Defensive patterns

Strategy: validation

Validate before calling

if (subscribeScheduler == null)
    throw new ArgumentNullException(nameof(subscribeScheduler));
if (disposeScheduler == null)
    throw new ArgumentNullException(nameof(disposeScheduler));

Type guard

bool SchedulersValid(IAsyncScheduler? s, IAsyncScheduler? d) => s is not null && d is not null;

Try / catch

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

Prevention

When it happens

Trigger: Calling source.SubscribeOn(source, null, disposeScheduler) — typically when the subscribe scheduler was meant to be inferred or was misassigned; also happens when constructing the tuple of schedulers from config where one entry is missing.

Common situations: Config only defines a dispose scheduler; a scheduler field initialized asynchronously and read before assignment; copy-paste from the single-scheduler overload leaving one argument null.

Related errors


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

Appendix: source

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

{
    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) =>
                {
                    var m = new SingleAssignmentAsyncDisposable();
                    var d = new SerialAsyncDisposable();

                    await d.AssignAsync(m).ConfigureAwait(false);

                    var scheduled = await state.subscribeScheduler.ScheduleAsync(async ct =>
                    {
                        var subscription = await source.SubscribeSafeAsync(observer).RendezVous(state.subscribeScheduler, ct);

                        var scheduledDispose = AsyncDisposable.Create(async () =>

View on GitHub (pinned to 94b5d5ab91)