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

What it means

Memoize(source, readerCount) validates that readerCount is a positive integer. When readerCount is zero or negative, the library throws ArgumentOutOfRangeException naming 'readerCount'. The reader count is the number of enumerators allowed to independently consume the memoized buffer, so a non-positive value is meaningless.

Solutions

  1. Pass a positive readerCount (>= 1) matching the number of concurrent enumerators you expect.
  2. Validate/clamp the value before calling: if (readerCount < 1) readerCount = 1;
  3. If you don't need a bounded reader count, use the parameterless Memoize(source) overload.

Example fix

// before
var buffer = source.Memoize(readerCount); // readerCount is 0
// after
if (readerCount < 1) readerCount = 1;
var buffer = source.Memoize(readerCount);
Defensive patterns

Strategy: validation

Validate before calling

if (readerCount < 1) throw new ArgumentOutOfRangeException(nameof(readerCount), "Must be a positive integer.");
var buffer = source.Memoize(readerCount);

Type guard

static bool IsValidReaderCount(int n) => n >= 1;

Try / catch

try { buffer = source.Memoize(readerCount); }
catch (ArgumentOutOfRangeException ex) when (ex.ParamName == "readerCount") { buffer = source.Memoize(1); }

Prevention

When it happens

Trigger: Calling EnumerableEx.Memoize(source, readerCount) with readerCount <= 0 (e.g. Memoize(seq, 0) or Memoize(seq, -1)), often when readerCount is computed from a variable that defaults to 0 or comes from unparsed/failed configuration.

Common situations: Passing a default-initialized int (0) before setting the desired reader count; parsing a config value that failed and yielded 0; misreading the parameter as a capacity or buffer size and passing 0 for 'unlimited'.

Related errors


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

Appendix: source

Thrown at Ix.NET/Source/System.Interactive/System/Linq/Operators/Memoize.cs:81

        /// Creates a buffer with a view over the source sequence, causing a specified number of enumerators to obtain access
        /// to all of the sequence's elements without causing multiple enumerations over the source.
        /// </summary>
        /// <typeparam name="TSource">Source sequence element type.</typeparam>
        /// <param name="source">Source sequence.</param>
        /// <param name="readerCount">
        /// Number of enumerators that can access the underlying buffer. Once every enumerator has
        /// obtained an element from the buffer, the element is removed from the buffer.
        /// </param>
        /// <returns>
        /// Buffer enabling a specified number of enumerators to retrieve all elements from the shared source sequence,
        /// without duplicating source enumeration side-effects.
        /// </returns>
        public static IBuffer<TSource> Memoize<TSource>(this IEnumerable<TSource> source, int readerCount)
        {
            if (source == null)
                throw new ArgumentNullException(nameof(source));
            if (readerCount <= 0)
                throw new ArgumentOutOfRangeException(nameof(readerCount));

            return new MemoizedBuffer<TSource>(source.GetEnumerator(), readerCount);
        }

        /// <summary>
        /// Memoizes the source sequence within a selector function where a specified number of enumerators can get access to
        /// all of the sequence's elements without causing multiple enumerations over the source.
        /// </summary>
        /// <typeparam name="TSource">Source sequence element type.</typeparam>
        /// <typeparam name="TResult">Result sequence element type.</typeparam>
        /// <param name="source">Source sequence.</param>
        /// <param name="readerCount">
        /// Number of enumerators that can access the underlying buffer. Once every enumerator has
        /// obtained an element from the buffer, the element is removed from the buffer.
        /// </param>
        /// <param name="selector">
        /// Selector function with memoized access to the source sequence for a specified number of
        /// enumerators.

View on GitHub (pinned to 94b5d5ab91)