dotnet/reactive · error · ArgumentNullException

scheduler

Error message

scheduler

What it means

This time-based Skip overload requires an IAsyncScheduler to run the per-element duration timers; null is rejected at operator creation. Fix: pass a scheduler (e.g. TaskPoolAsyncScheduler.Default) or use the overload without an explicit scheduler.

Solutions

  1. Pass a valid scheduler such as TaskPoolAsyncScheduler.Default or the NewDefaultAsyncScheduler
  2. Fix DI registration so IAsyncScheduler is provided
  3. Use the two-argument Skip(source, duration) overload, which defaults to TaskPoolAsyncScheduler.Default

Example fix

// before
source.Skip(TimeSpan.FromSeconds(1), null);
// after
source.Skip(TimeSpan.FromSeconds(1), TaskPoolAsyncScheduler.Default);
Defensive patterns

Strategy: validation

Validate before calling

if (scheduler == null) scheduler = TaskPoolAsyncScheduler.Default;
var res = source.Skip(TimeSpan.FromSeconds(1), scheduler);

Type guard

bool IsValidScheduler(IAsyncScheduler s) => s != null;

Try / catch

try { var res = source.Skip(dur, scheduler); }
catch (ArgumentNullException ex) when (ex.ParamName == "scheduler") { res = source.Skip(dur); } // default scheduler overload

Prevention

When it happens

Trigger: Calling Skip(source, duration, null), e.g. a scheduler field/property not yet initialized or a DI-resolved scheduler that failed to register.

Common situations: Missing DI registration for IAsyncScheduler; using a scheduler obtained from a service that returned null; forgetting to pass TaskPoolAsyncScheduler.Default explicitly.

Related errors


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

Appendix: source

Thrown at AsyncRx.NET/System.Reactive.Async/Linq/Operators/Skip.cs:66

                duration,
                static async (source, duration, observer) =>
                {
                    var (sourceObserver, timer) = await AsyncObserver.Skip(observer, duration).ConfigureAwait(false);

                    var subscription = await source.SubscribeSafeAsync(sourceObserver).ConfigureAwait(false);

                    return StableCompositeAsyncDisposable.Create(subscription, timer);
                });
        }

        public static IAsyncObservable<TSource> Skip<TSource>(this IAsyncObservable<TSource> source, TimeSpan duration, IAsyncScheduler scheduler)
        {
            if (source == null)
                throw new ArgumentNullException(nameof(source));
            if (duration < TimeSpan.Zero)
                throw new ArgumentOutOfRangeException(nameof(duration));
            if (scheduler == null)
                throw new ArgumentNullException(nameof(scheduler));

            if (duration == TimeSpan.Zero)
            {
                return source;
            }

            // REVIEW: May be easier to just use SkipUntil with a Timer parameter. Do we want Skip on the observer?

            return CreateAsyncObservable<TSource>.From(
                source,
                (duration, scheduler),
                static async (source, state, observer) =>
                {
                    var (sourceObserver, timer) = await AsyncObserver.Skip(observer, state.duration).ConfigureAwait(false);

                    var subscription = await source.SubscribeSafeAsync(sourceObserver).ConfigureAwait(false);

                    return StableCompositeAsyncDisposable.Create(subscription, timer);

View on GitHub (pinned to 94b5d5ab91)