dotnet/reactive · error · ArgumentOutOfRangeException

duration

Error message

duration

What it means

TakeLastBuffer(source, duration) rejects negative TimeSpans with ArgumentOutOfRangeException. A negative window is meaningless for 'buffer the last duration worth of elements'; TimeSpan.Zero is allowed and returns an empty buffer observable.

Solutions

  1. Pass a non-negative TimeSpan; clamp negatives to TimeSpan.Zero.
  2. Fix the window computation so end >= start.
  3. Validate configured durations at application startup.

Example fix

// before
var buf = source.TakeLastBuffer(window); // window may be negative
// after
var safeWindow = window < TimeSpan.Zero ? TimeSpan.Zero : window;
var buf = source.TakeLastBuffer(safeWindow);
Defensive patterns

Strategy: validation

Validate before calling

if (duration < TimeSpan.Zero) throw new ArgumentOutOfRangeException(nameof(duration));
source.TakeLastBuffer(duration);

Try / catch

try { var buf = source.TakeLastBuffer(duration); }
catch (ArgumentOutOfRangeException ex) when (ex.ParamName == "duration") { /* clamp to TimeSpan.Zero */ }

Prevention

When it happens

Trigger: source.TakeLastBuffer(TimeSpan.FromSeconds(-5)) — from timestamp subtraction in the wrong order or negative config values.

Common situations: Computing windows from DateTime differences incorrectly; user-supplied retention windows parsed without validation; timezone/DST arithmetic producing negative deltas.

Related errors


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

Appendix: source

Thrown at AsyncRx.NET/System.Reactive.Async/Linq/Operators/TakeLastBuffer.cs:36

                throw new ArgumentOutOfRangeException(nameof(count));

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

            return CreateAsyncObservable<IList<TSource>>.From(
                source,
                count,
                static (source, count, observer) => source.SubscribeSafeAsync(AsyncObserver.TakeLastBuffer(observer, count)));
        }

        public static IAsyncObservable<IList<TSource>> TakeLastBuffer<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<IList<TSource>>();
            }

            return CreateAsyncObservable<IList<TSource>>.From(
                source,
                duration,
                static (source, duration, observer) => source.SubscribeSafeAsync(AsyncObserver.TakeLastBuffer(observer, duration)));
        }

        public static IAsyncObservable<IList<TSource>> TakeLastBuffer<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));

View on GitHub (pinned to 94b5d5ab91)