dotnet/reactive · error · ArgumentOutOfRangeException

Specified argument was out of range of valid values…

Error message

Specified argument was out of range of valid values. (Parameter 'duration')

What it means

Take(source, duration) requires a non-negative TimeSpan; a negative duration is invalid (it would mean taking elements from before the start) and throws ArgumentOutOfRangeException. TimeSpan.Zero is valid and yields an empty observable.

Solutions

  1. Clamp the duration: if (d < TimeSpan.Zero) d = TimeSpan.Zero;
  2. Return Empty<T>() early when the computed window is non-positive
  3. Validate configured duration values at startup

Example fix

// before
var window = source.Take(deadline - DateTime.Now); // may be negative
// after
var d = deadline - DateTime.Now;
var window = d > TimeSpan.Zero ? source.Take(d) : AsyncObservable.Empty<T>();
Defensive patterns

Strategy: validation

Validate before calling

if (duration < TimeSpan.Zero) throw new ArgumentOutOfRangeException(nameof(duration));
var window = source.Take(duration);

Type guard

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

Try / catch

try { var window = source.Take(duration); }
catch (ArgumentOutOfRangeException ex) when (ex.ParamName == "duration") { /* treat as elapsed: use Empty */ }

Prevention

When it happens

Trigger: Calling source.Take(negativeTimeSpan), typically from a computed window such as endTime - now when now is past endTime.

Common situations: Deadline-based windows where the deadline already elapsed, or a configuration value parsed as a negative duration.

Related errors


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

Appendix: source

Thrown at AsyncRx.NET/System.Reactive.Async/Linq/Operators/Take.cs:37

                throw new ArgumentOutOfRangeException(nameof(count));

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

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

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

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

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

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

                    return StableCompositeAsyncDisposable.Create(subscription, timer);

View on GitHub (pinned to 94b5d5ab91)