dotnet/reactive · error · ArgumentNullException
disposeScheduler
Error message
disposeScheduler
What it means
SubscribeOn(source, subscribeScheduler, disposeScheduler) validates the dispose scheduler last. A null disposeScheduler throws ArgumentNullException("disposeScheduler") because resource disposition must be scheduled onto it.
Solutions
- Use the single-scheduler overload SubscribeOn(source, scheduler) if both phases should use one scheduler.
- Pass a valid dispose scheduler instance explicitly.
- Fix whatever returns/assigns null to the dispose scheduler.
Example fix
// before var obs = source.SubscribeOn(subscribeScheduler, null); // after var obs = source.SubscribeOn(subscribeScheduler); // same scheduler for subscribe and dispose
Defensive patterns
Strategy: validation
Validate before calling
if (disposeScheduler == null)
disposeScheduler = subscribeScheduler; // or AsyncScheduler.DefaultScheduler Type guard
bool HasDisposeScheduler(IAsyncScheduler? d) => d is not null;
Try / catch
try
{
var obs = source.SubscribeOn(subscribeScheduler, disposeScheduler);
}
catch (ArgumentNullException ex) when (ex.ParamName == "disposeScheduler")
{
logger.LogError(ex, "Null dispose scheduler");
obs = source.SubscribeOn(subscribeScheduler);
} Prevention
- If no separate dispose scheduler is needed, use SubscribeOn(source, scheduler).
- Initialize dispose scheduler fields together with subscribe scheduler fields.
- Document config keys for both schedulers and fail fast at startup if missing.
When it happens
Trigger: Calling source.SubscribeOn(subscribeScheduler, null) — often when the caller believes disposal reuses the subscribe scheduler, or the dispose scheduler variable was never assigned.
Common situations: Simplifying a call by dropping an argument; config lacking a separate dispose scheduler; refactoring from the single-scheduler overload leaving the second parameter null.
Related errors
- Argument cannot be null (Parameter name: scheduler)
- nameof(scheduler)
- new ArgumentNullException(nameof(scheduler))
- new ArgumentNullException(nameof(timeSelector))
- scheduler
AI-assisted analysis of dotnet/reactive@94b5d5ab91 (2026-09-15).
Data as JSON: /api/errors/b3a16dd24790651b.
Report an issue: GitHub.
Appendix: source
Thrown at AsyncRx.NET/System.Reactive.Async/Linq/Operators/SubscribeOn.cs:29
{
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 () =>
{
await state.disposeScheduler.ScheduleAsync(async _ =>View on GitHub (pinned to 94b5d5ab91)