dotnet/reactive · error · ArgumentOutOfRangeException

Specified argument was out of the range of valid values…

Error message

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

What it means

This ArgumentOutOfRangeException is thrown by the time-based Window helper when timeSpan is negative (less than TimeSpan.Zero). Zero is allowed (windows close immediately per tick semantics), but a negative duration has no meaning for a timer-based window. The check runs synchronously before any scheduling occurs.

Solutions

  1. Pass a non-negative TimeSpan such as TimeSpan.FromSeconds(5).
  2. Clamp: if (ts < TimeSpan.Zero) ts = TimeSpan.Zero; or throw your own validation error earlier.
  3. Fix the config/parser so durations are validated as non-negative at load time.
  4. Check any date/duration arithmetic producing the TimeSpan for reversed operands.

Example fix

// before
var ts = end - start; // end earlier than start => negative
var windows = source.Window(ts);
// after
var ts = end > start ? end - start : TimeSpan.Zero;
var windows = source.Window(ts);
Defensive patterns

Strategy: validation

Validate before calling

if (timeSpan < TimeSpan.Zero) throw new ArgumentOutOfRangeException(nameof(timeSpan), timeSpan, "Window duration must be non-negative.");
// or clamp: timeSpan = timeSpan < TimeSpan.Zero ? TimeSpan.Zero : timeSpan;

Type guard

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

Try / catch

try
{
    var windows = source.Window(timeSpan);
}
catch (ArgumentOutOfRangeException ex) when (ex.ParamName == "timeSpan")
{
    timeSpan = DefaultWindowDuration; // e.g. TimeSpan.FromSeconds(1)
}

Prevention

When it happens

Trigger: Calling Window(source, timeSpan) or the internal helper with a negative TimeSpan, e.g. a value read from config in milliseconds that was negative, or subtracting TimeSpans in the wrong order.

Common situations: Duration configuration parsed as a signed number; clock arithmetic (end - start with end < start); serialization of durations that lost sign constraints.

Related errors


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

Appendix: source

Thrown at AsyncRx.NET/System.Reactive.Async/Linq/Operators/Window.cs:295

                            }

                            await observer.OnCompletedAsync().ConfigureAwait(false);
                        }
                    ),
                    refCount
                );
        }

        public static ValueTask<(IAsyncObserver<TSource>, IAsyncDisposable)> Window<TSource>(IAsyncObserver<IAsyncObservable<TSource>> observer, IAsyncDisposable subscription, TimeSpan timeSpan) => Window(observer, subscription, timeSpan, TaskPoolAsyncScheduler.Default);

        public static ValueTask<(IAsyncObserver<TSource>, IAsyncDisposable)> Window<TSource>(IAsyncObserver<IAsyncObservable<TSource>> observer, IAsyncDisposable subscription, TimeSpan timeSpan, IAsyncScheduler scheduler)
        {
            if (observer == null)
                throw new ArgumentNullException(nameof(observer));
            if (subscription == null)
                throw new ArgumentNullException(nameof(subscription));
            if (timeSpan < TimeSpan.Zero)
                throw new ArgumentOutOfRangeException(nameof(timeSpan));
            if (scheduler == null)
                throw new ArgumentNullException(nameof(scheduler));

            var gate = new AsyncGate();

            var window = default(IAsyncSubject<TSource>);
            var d = new CompositeAsyncDisposable();
            var refCount = new RefCountAsyncDisposable(d);

            async Task CreateWindowAsync()
            {
                window = new SequentialSimpleAsyncSubject<TSource>();

                var wrapper = new WindowAsyncObservable<TSource>(window, refCount);

                await observer.OnNextAsync(wrapper).ConfigureAwait(false);
            }

View on GitHub (pinned to 94b5d5ab91)