dotnet/reactive · error · ArgumentNullException

clock

Error message

clock

What it means

TakeLast(source, duration, clock) throws ArgumentNullException("clock") because this overload requires an explicit IClock to define 'now' for the time window. Null is rejected eagerly with the parameter name instead of failing during subscription.

Solutions

  1. Pass a concrete IClock (system clock or test/virtual clock) instance
  2. Use the TakeLast(source, duration) overload when the default clock suffices
  3. Fix the clock provider/DI registration so it yields a non-null instance

Example fix

// before
var result = source.TakeLast(TimeSpan.FromSeconds(5), (IClock)null);
// after
var result = source.TakeLast(TimeSpan.FromSeconds(5), clock); // injected IClock
// or: var result = source.TakeLast(TimeSpan.FromSeconds(5));
Defensive patterns

Strategy: validation

Validate before calling

if (clock is null) throw new InvalidOperationException("IClock must be resolved before calling TakeLast");
var result = source.TakeLast(duration, clock);

Type guard

bool HasClock(IClock? c) => c is not null;

Try / catch

try { var r = source.TakeLast(duration, clock); }
catch (ArgumentNullException ex) when (ex.ParamName == "clock") { var r = source.TakeLast(duration); }

Prevention

When it happens

Trigger: Calling TakeLast(source, duration, (IClock)null), or passing a clock obtained from an accessor that returned null.

Common situations: Test code forgetting to supply a fake/test clock; DI container not registered for IClock; refactoring from the two-argument overload and adding a null clock placeholder.

Related errors


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

Appendix: source

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

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

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

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

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

            if (duration == TimeSpan.Zero)
            {
                return Empty<TSource>();
            }

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

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

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

View on GitHub (pinned to 94b5d5ab91)