dotnet/reactive · error · ArgumentNullException

scheduler

Error message

scheduler

What it means

The Replay(source, selector, bufferSize, scheduler) overload throws ArgumentNullException because the IAsyncScheduler passed was null. The scheduler drives the sequential replay subject's timing, so a null scheduler would break replay behavior. Validation happens eagerly when Replay is called.

Solutions

  1. Pass a concrete scheduler such as Scheduler.Default.Async or your configured IAsyncScheduler instance.
  2. Check why the scheduler variable is null (DI registration, initialization order) and fix it.
  3. Fall back to a default scheduler when none is configured: scheduler ?? Scheduler.Default.Async.

Example fix

// before
var replayed = source.Replay(selector, 10, scheduler); // scheduler == null
// after
var replayed = source.Replay(selector, 10, scheduler ?? Scheduler.Default.Async);
Defensive patterns

Strategy: validation

Validate before calling

if (scheduler is null) throw new InvalidOperationException("scheduler must be provided");
// safe to call source.Replay(selector, bufferSize, scheduler);

Type guard

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

Try / catch

try { var r = source.Replay(selector, bufferSize, scheduler); }
catch (ArgumentNullException ex) when (ex.ParamName == "scheduler") { /* fall back to Scheduler.Default.Async */ }

Prevention

When it happens

Trigger: Calling source.Replay(selector, bufferSize, null), or passing a scheduler property/field that was never initialized (e.g. a null injected dependency).

Common situations: Dependency-injected scheduler not registered in the container; static scheduler field not yet assigned; test code omitting the scheduler argument by passing null intentionally.

Related errors


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

Appendix: source

Thrown at AsyncRx.NET/System.Reactive.Async/Linq/Operators/Replay.cs:146

                throw new ArgumentNullException(nameof(source));
            if (selector == null)
                throw new ArgumentNullException(nameof(selector));
            if (bufferSize < 0)
                throw new ArgumentOutOfRangeException(nameof(bufferSize));

            return Multicast(source, () => new SequentialReplayAsyncSubject<TSource>(bufferSize), selector);
        }

        public static IAsyncObservable<TResult> Replay<TSource, TResult>(this IAsyncObservable<TSource> source, Func<IAsyncObservable<TSource>, IAsyncObservable<TResult>> selector, int bufferSize, IAsyncScheduler scheduler)
        {
            if (source == null)
                throw new ArgumentNullException(nameof(source));
            if (selector == null)
                throw new ArgumentNullException(nameof(selector));
            if (bufferSize < 0)
                throw new ArgumentOutOfRangeException(nameof(bufferSize));
            if (scheduler == null)
                throw new ArgumentNullException(nameof(scheduler));

            return Multicast(source, () => new SequentialReplayAsyncSubject<TSource>(bufferSize, scheduler), selector);
        }

        public static IAsyncObservable<TResult> Replay<TSource, TResult>(this IAsyncObservable<TSource> source, Func<IAsyncObservable<TSource>, IAsyncObservable<TResult>> selector, TimeSpan window)
        {
            if (source == null)
                throw new ArgumentNullException(nameof(source));
            if (selector == null)
                throw new ArgumentNullException(nameof(selector));
            if (window < TimeSpan.Zero)
                throw new ArgumentOutOfRangeException(nameof(window));

            return Multicast(source, () => new SequentialReplayAsyncSubject<TSource>(window), selector);
        }

        public static IAsyncObservable<TResult> Replay<TSource, TResult>(this IAsyncObservable<TSource> source, Func<IAsyncObservable<TSource>, IAsyncObservable<TResult>> selector, TimeSpan window, IAsyncScheduler scheduler)
        {

View on GitHub (pinned to 94b5d5ab91)