dotnet/reactive · error · ArgumentNullException

scheduler

Error message

scheduler

What it means

TakeLast(source, count, scheduler) throws ArgumentNullException("scheduler") because the overload requires an explicit IAsyncScheduler to schedule the timing window. The Rx.NET Async operators validate all reference arguments eagerly at call time rather than surfacing nulls later inside the subscription pipeline. Passing a null scheduler is a programming error, so it fails fast with the parameter name.

Solutions

  1. Pass a concrete IAsyncScheduler instance, e.g. the library's default/scheduler provider for your concurrency model
  2. Use the TakeLast(source, count) overload instead if no scheduler customization is needed
  3. Guard or assert the scheduler variable before calling, ensuring DI resolution produced a non-null instance

Example fix

// before
var result = source.TakeLast(5, (IAsyncScheduler)null);
// after
var result = source.TakeLast(5, scheduler); // scheduler resolved from provider/DI
// or: var result = source.TakeLast(5);
Defensive patterns

Strategy: validation

Validate before calling

if (scheduler is null) throw new InvalidOperationException("scheduler must be provided before calling TakeLast");
var result = source.TakeLast(5, scheduler);

Type guard

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

Try / catch

try { var r = source.TakeLast(5, scheduler); }
catch (ArgumentNullException ex) when (ex.ParamName == "scheduler") { /* fall back to parameterless overload */ var r = source.TakeLast(5); }

Prevention

When it happens

Trigger: Calling TakeLast with a non-null source and non-negative count but scheduler == null, e.g. TakeLast(source, 5, (IAsyncScheduler)null).

Common situations: Refactoring from the TakeLast(source, count) overload and adding a scheduler argument that is still null; a scheduler variable resolved from DI/config that returned null; conditional scheduler selection leaving the variable unset.

Related errors


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

Appendix: source

Thrown at AsyncRx.NET/System.Reactive.Async/Linq/Operators/TakeLast.cs:46

                count,
                static async (source, count, observer) =>
                {
                    var (sink, drain) = AsyncObserver.TakeLast(observer, count);

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

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

        public static IAsyncObservable<TSource> TakeLast<TSource>(this IAsyncObservable<TSource> source, int count, IAsyncScheduler scheduler)
        {
            if (source == null)
                throw new ArgumentNullException(nameof(source));
            if (count < 0)
                throw new ArgumentOutOfRangeException(nameof(count));
            if (scheduler == null)
                throw new ArgumentNullException(nameof(scheduler));

            if (count == 0)
            {
                return Empty<TSource>();
            }

            return CreateAsyncObservable<TSource>.From(
                source,
                (count, scheduler),
                static async (source, state, observer) =>
                {
                    var (sink, drain) = AsyncObserver.TakeLast(observer, state.count, state.scheduler);

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

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

View on GitHub (pinned to 94b5d5ab91)