dotnet/reactive · error · ArgumentOutOfRangeException

duration

Error message

duration

What it means

TakeLast(source, duration) throws ArgumentOutOfRangeException("duration") when the TimeSpan is negative. A negative duration is meaningless for a 'take the last items within this window' operator, so the library rejects it up front with the parameter name.

Solutions

  1. Clamp or validate the duration to TimeSpan.Zero or greater before calling
  2. Use TimeSpan.Zero explicitly when the intent is an empty result (the operator returns Empty for zero)
  3. Fix the computation producing the negative TimeSpan (swapped operands, wrong clock)

Example fix

// before
var result = source.TakeLast(end - start); // end < start -> negative
// after
var duration = end > start ? end - start : TimeSpan.Zero;
var result = source.TakeLast(duration);
Defensive patterns

Strategy: validation

Validate before calling

if (duration < TimeSpan.Zero) duration = TimeSpan.Zero;
var result = source.TakeLast(duration);

Type guard

bool IsValidDuration(TimeSpan d) => d >= TimeSpan.Zero;

Try / catch

try { var r = source.TakeLast(duration); }
catch (ArgumentOutOfRangeException ex) when (ex.ParamName == "duration") { var r = source.TakeLast(TimeSpan.Zero); }

Prevention

When it happens

Trigger: Calling source.TakeLast(TimeSpan.FromMilliseconds(-1)) or passing a duration computed from clock differences that came out negative.

Common situations: Computing a window as endTime - startTime where the values were swapped or the clock was non-monotonic; user/config-supplied durations parsed without sign validation; arithmetic on subtracted TimeSpans underflowing intent.

Related errors


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

Appendix: source

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

            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);
                });
        }

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

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

            return CreateAsyncObservable<TSource>.From(
                source,
                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);
                });
        }

View on GitHub (pinned to 94b5d5ab91)