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

What it means

Replay(source, bufferSize) throws ArgumentOutOfRangeException('bufferSize') when bufferSize is negative. The replay buffer size must be >= 0; a negative value cannot describe a valid number of notifications to retain.

Solutions

  1. Pass a non-negative bufferSize (0 replays nothing).
  2. If unbounded replay is intended, use the parameterless source.Replay() overload which keeps all notifications.
  3. Clamp the value: Math.Max(0, requestedSize).

Example fix

// before
var size = config.BufferSize ?? -1; // -1 meant 'unbounded'
var replay = source.Replay(size);
// after
var replay = config.BufferSize.HasValue ? source.Replay(Math.Max(0, config.BufferSize.Value)) : source.Replay();
Defensive patterns

Strategy: validation

Validate before calling

if (bufferSize < 0)
    throw new ArgumentOutOfRangeException(nameof(bufferSize), bufferSize, "Buffer size must be non-negative.");
var replay = source.Replay(bufferSize);

Type guard

static bool IsValidBufferSize(int bufferSize) => bufferSize >= 0;

Try / catch

try
{
    var replay = source.Replay(bufferSize);
}
catch (ArgumentOutOfRangeException ex) when (ex.ParamName == "bufferSize")
{
    var replay = source.Replay(); // fall back to unbounded
}

Prevention

When it happens

Trigger: Calling source.Replay(bufferSize) with bufferSize < 0, e.g. -1 used as a sentinel for 'unbounded', or a computed size that underflowed.

Common situations: Porting from APIs where -1 means 'infinite buffer'; config values that are negative; integer arithmetic producing a negative count (e.g. size - extra when extra > size).

Related errors


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

Appendix: source

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

            return Multicast(source, new SequentialReplayAsyncSubject<TSource>());
        }

        public static IConnectableAsyncObservable<TSource> Replay<TSource>(this IAsyncObservable<TSource> source, IAsyncScheduler scheduler)
        {
            if (source == null)
                throw new ArgumentNullException(nameof(source));
            if (scheduler == null)
                throw new ArgumentNullException(nameof(scheduler));

            return Multicast(source, new SequentialReplayAsyncSubject<TSource>(scheduler));
        }

        public static IConnectableAsyncObservable<TSource> Replay<TSource>(this IAsyncObservable<TSource> source, int bufferSize)
        {
            if (source == null)
                throw new ArgumentNullException(nameof(source));
            if (bufferSize < 0)
                throw new ArgumentOutOfRangeException(nameof(bufferSize));

            return Multicast(source, new SequentialReplayAsyncSubject<TSource>(bufferSize));
        }

        public static IConnectableAsyncObservable<TSource> Replay<TSource>(this IAsyncObservable<TSource> source, int bufferSize, IAsyncScheduler scheduler)
        {
            if (source == null)
                throw new ArgumentNullException(nameof(source));
            if (bufferSize < 0)
                throw new ArgumentOutOfRangeException(nameof(bufferSize));
            if (scheduler == null)
                throw new ArgumentNullException(nameof(scheduler));

            return Multicast(source, new SequentialReplayAsyncSubject<TSource>(bufferSize, scheduler));
        }

        public static IConnectableAsyncObservable<TSource> Replay<TSource>(this IAsyncObservable<TSource> source, TimeSpan window)
        {

View on GitHub (pinned to 94b5d5ab91)