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 'timeShift')

What it means

In the sliding time Window, timeShift is the interval between window starts and must be non-negative. The operator throws ArgumentOutOfRangeException when it is negative because window start times would regress in time, an unschedulable configuration.

Solutions

  1. Clamp or recompute the shift to be >= TimeSpan.Zero before calling Window
  2. Check argument order — ensure timeSpan (length) is passed before timeShift (period)
  3. Fix the producer of the negative duration (config parsing, timestamp subtraction)

Example fix

// before
await AsyncObservable.Window(observer, subscription, shift, windowLen, scheduler); // args swapped
// after
await AsyncObservable.Window(observer, subscription, windowLen, shift < TimeSpan.Zero ? TimeSpan.Zero : shift, scheduler);
Defensive patterns

Strategy: validation

Validate before calling

if (timeShift < TimeSpan.Zero) throw new ArgumentOutOfRangeException(nameof(timeShift));
var safeShift = TimeSpan.Max(TimeSpan.Zero, timeShift);

Type guard

static bool IsValidShift(TimeSpan t) => t >= TimeSpan.Zero;

Try / catch

try
{
    await AsyncObservable.Window(observer, subscription, timeSpan, timeShift, scheduler);
}
catch (ArgumentOutOfRangeException ex) when (ex.ParamName == "timeShift")
{
    // fix argument order or clamp the shift
}

Prevention

When it happens

Trigger: Passing a negative TimeSpan as the timeShift argument (4th parameter) of Window(observer, subscription, timeSpan, timeShift[, scheduler]) — e.g. a computed shift that went negative or swapped the timeShift/timeSpan arguments.

Common situations: Swapping timeSpan and timeShift where one is negative; deriving the shift from a percentage or delta that can go below zero; parsing durations from settings where negatives are not screened.

Related errors


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

Appendix: source

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

                        refCount
                    );
            }

            return CoreAsync();
        }

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

        public static ValueTask<(IAsyncObserver<TSource>, IAsyncDisposable)> Window<TSource>(IAsyncObserver<IAsyncObservable<TSource>> observer, IAsyncDisposable subscription, TimeSpan timeSpan, TimeSpan timeShift, 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 (timeShift < TimeSpan.Zero)
                throw new ArgumentOutOfRangeException(nameof(timeShift));
            if (scheduler == null)
                throw new ArgumentNullException(nameof(scheduler));

            var gate = new AsyncGate();

            var d = new CompositeAsyncDisposable();
            var timer = new SerialAsyncDisposable();
            var refCount = new RefCountAsyncDisposable(d);

            var queue = new Queue<IAsyncSubject<TSource>>();

            var nextOpen = timeShift;
            var nextClose = timeSpan;
            var totalTime = TimeSpan.Zero;

            var isOpen = false;
            var isClose = false;

View on GitHub (pinned to 94b5d5ab91)