dotnet/reactive · error · ArgumentOutOfRangeException

throw new ArgumentOutOfRangeException(nameof(window));

Error message

throw new ArgumentOutOfRangeException(nameof(window));

What it means

The Replay(source, selector, bufferSize, window) operator validates the replay window and throws ArgumentOutOfRangeException when window is a negative TimeSpan. A negative expiration window for replayed items is meaningless, so the guard rejects it before constructing the SequentialReplayAsyncSubject.

Solutions

  1. Pass TimeSpan.Zero or a positive TimeSpan for the window.
  2. Clamp before calling: window = window < TimeSpan.Zero ? TimeSpan.Zero : window.
  3. Validate configured durations at load time (reject negatives with a clear message).

Example fix

// before
var replayed = AsyncObservable.Replay(source, sel, 10, window: TimeSpan.FromSeconds(-5));
// after
var replayed = AsyncObservable.Replay(source, sel, 10, window: TimeSpan.FromSeconds(5));
Defensive patterns

Strategy: validation

Validate before calling

if (window < TimeSpan.Zero) throw new ArgumentException("window must be non-negative", nameof(window));

Try / catch

try { var replayed = AsyncObservable.Replay(source, sel, bufferSize, window); } catch (ArgumentOutOfRangeException ex) when (ex.ParamName == "window") { /* fall back to TimeSpan.Zero */ }

Prevention

When it happens

Trigger: Calling AsyncObservable.Replay(source, selector, bufferSize, window) with a TimeSpan less than TimeSpan.Zero, e.g. a window parsed from a negative configured value or computed as an earlier timestamp minus a later one.

Common situations: Timespan parsed from config where the user entered '-5' intending seconds of magnitude; computing a duration by subtracting DateTime/Stopwatch values in the wrong order; unit tests passing TimeSpan.MinValue.

Related errors


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

Appendix: source

Thrown at AsyncRx.NET/System.Reactive.Async/Linq/Operators/Replay.cs:290

                throw new ArgumentNullException(nameof(selector));
            if (window < TimeSpan.Zero)
                throw new ArgumentOutOfRangeException(nameof(window));
            if (scheduler == null)
                throw new ArgumentNullException(nameof(scheduler));

            return Multicast(source, () => new ValueTask<IAsyncSubject<TSource, TSource>>(new SequentialReplayAsyncSubject<TSource>(window, scheduler)), selector);
        }

        public static IAsyncObservable<TResult> Replay<TSource, TResult>(this IAsyncObservable<TSource> source, Func<IAsyncObservable<TSource>, ValueTask<IAsyncObservable<TResult>>> selector, int bufferSize, TimeSpan window)
        {
            if (source == null)
                throw new ArgumentNullException(nameof(source));
            if (selector == null)
                throw new ArgumentNullException(nameof(selector));
            if (bufferSize < 0)
                throw new ArgumentOutOfRangeException(nameof(bufferSize));
            if (window < TimeSpan.Zero)
                throw new ArgumentOutOfRangeException(nameof(window));

            return Multicast(source, () => new ValueTask<IAsyncSubject<TSource, TSource>>(new SequentialReplayAsyncSubject<TSource>(bufferSize, window)), selector);
        }

        public static IAsyncObservable<TResult> Replay<TSource, TResult>(this IAsyncObservable<TSource> source, Func<IAsyncObservable<TSource>, ValueTask<IAsyncObservable<TResult>>> selector, int bufferSize, TimeSpan window, IAsyncScheduler scheduler)
        {
            if (source == null)
                throw new ArgumentNullException(nameof(source));
            if (selector == null)
                throw new ArgumentNullException(nameof(selector));
            if (bufferSize < 0)
                throw new ArgumentOutOfRangeException(nameof(bufferSize));
            if (window < TimeSpan.Zero)
                throw new ArgumentOutOfRangeException(nameof(window));
            if (scheduler == null)
                throw new ArgumentNullException(nameof(scheduler));

            return Multicast(source, () => new ValueTask<IAsyncSubject<TSource, TSource>>(new SequentialReplayAsyncSubject<TSource>(bufferSize, window, scheduler)), selector);

View on GitHub (pinned to 94b5d5ab91)