dotnet/reactive · error · ArgumentOutOfRangeException

throw new ArgumentOutOfRangeException(nameof(bufferSize));

Error message

throw new ArgumentOutOfRangeException(nameof(bufferSize));

What it means

The Replay(source, selector, bufferSize, window) operator validates bufferSize before creating a SequentialReplayAsyncSubject. It throws ArgumentOutOfRangeException when bufferSize is negative, because a replay buffer cannot hold a negative number of items. Only negative values are rejected; 0 is allowed (no buffered history, only live notification).

Solutions

  1. Pass a non-negative bufferSize (0 for replay-live-only, int.MaxValue for unlimited history).
  2. Clamp the value before the call: bufferSize = Math.Max(0, computedSize).
  3. Validate configuration inputs at startup so negative sizes never reach the operator.

Example fix

// before
var replayed = AsyncObservable.Replay(source, sel, bufferSize: -1, window: TimeSpan.FromSeconds(5));
// after
if (bufferSize < 0) bufferSize = 0;
var replayed = AsyncObservable.Replay(source, sel, bufferSize, window: TimeSpan.FromSeconds(5));
Defensive patterns

Strategy: validation

Validate before calling

if (bufferSize < 0) throw new ArgumentException("bufferSize must be >= 0", nameof(bufferSize));

Try / catch

try { var replayed = AsyncObservable.Replay(source, sel, bufferSize, window); } catch (ArgumentOutOfRangeException ex) when (ex.ParamName == "bufferSize") { /* use 0 or int.MaxValue and retry construction */ }

Prevention

When it happens

Trigger: Calling AsyncObservable.Replay(source, selector, bufferSize, window) with a bufferSize parameter that is < 0, e.g. a computed size from an unvalidated config value or a subtraction underflow like newSize - removedItems.

Common situations: Reading bufferSize from appsettings/environment variables without validation; computing a buffer size with integer arithmetic that goes negative; copying a call site from another operator and passing an unrelated negative value.

Related errors


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

Appendix: source

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

                throw new ArgumentNullException(nameof(source));
            if (selector == null)
                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));

View on GitHub (pinned to 94b5d5ab91)