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

What it means

This GroupBy overload accepts an initial capacity hint for the per-group dictionaries. Because a negative capacity is meaningless, the operator validates it up front and throws ArgumentOutOfRangeException naming 'capacity'. The value is only a sizing hint, so any non-negative value is accepted.

Solutions

  1. Clamp or validate the capacity before the call: if (capacity < 0) capacity = 0; or use Math.Max(0, n).
  2. Omit the capacity argument and use an overload without it (defaults to int.MaxValue).
  3. Fix the upstream computation that produced the negative number.

Example fix

// before
var grouped = source.GroupBy(x => x.Key, x => x, items.Length - skipped);
// after
var capacity = Math.Max(0, items.Length - skipped);
var grouped = source.GroupBy(x => x.Key, x => x, capacity);
Defensive patterns

Strategy: validation

Validate before calling

if (capacity < 0) throw new ArgumentOutOfRangeException(nameof(capacity), capacity, "Capacity must be non-negative.");
var grouped = source.GroupBy(keySelector, elementSelector, capacity);

Type guard

bool IsValidCapacity(int capacity) => capacity >= 0;

Try / catch

try
{
    grouped = source.GroupBy(keySelector, elementSelector, capacity);
}
catch (ArgumentOutOfRangeException ex) when (ex.ParamName == "capacity")
{
    grouped = source.GroupBy(keySelector, elementSelector); // default capacity
}

Prevention

When it happens

Trigger: Calling AsyncObservable.GroupBy(source, keySelector, elementSelector, capacity) with a negative capacity value, typically computed from a variable (e.g. list.Count - offset when offset > Count).

Common situations: Capacity computed from user input, configuration, or subtraction that can go negative; passing -1 as a 'default' sentinel; integer arithmetic on sizes that underflows.

Related errors


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

Appendix: source

Thrown at AsyncRx.NET/System.Reactive.Async/Linq/Operators/GroupBy.cs:243

            if (comparer == null)
                throw new ArgumentNullException(nameof(comparer));

            return CreateAsyncObservable<IGroupedAsyncObservable<TKey, TElement>>.From(
                source,
                (keySelector, elementSelector, comparer),
                static (source, state, observer) => GroupByCore(source, observer, (o, d) => AsyncObserver.GroupBy(o, d, state.keySelector, state.elementSelector, state.comparer)));
        }

        public static IAsyncObservable<IGroupedAsyncObservable<TKey, TElement>> GroupBy<TSource, TKey, TElement>(this IAsyncObservable<TSource> source, Func<TSource, ValueTask<TKey>> keySelector, Func<TSource, ValueTask<TElement>> elementSelector, int capacity)
        {
            if (source == null)
                throw new ArgumentNullException(nameof(source));
            if (keySelector == null)
                throw new ArgumentNullException(nameof(keySelector));
            if (elementSelector == null)
                throw new ArgumentNullException(nameof(elementSelector));
            if (capacity < 0)
                throw new ArgumentOutOfRangeException(nameof(capacity));

            return CreateAsyncObservable<IGroupedAsyncObservable<TKey, TElement>>.From(
                source,
                (keySelector, elementSelector, capacity),
                static (source, state, observer) => GroupByCore(source, observer, (o, d) => AsyncObserver.GroupBy(o, d, state.keySelector, state.elementSelector, state.capacity)));
        }

        public static IAsyncObservable<IGroupedAsyncObservable<TKey, TElement>> GroupBy<TSource, TKey, TElement>(this IAsyncObservable<TSource> source, Func<TSource, ValueTask<TKey>> keySelector, Func<TSource, ValueTask<TElement>> elementSelector, int capacity, IEqualityComparer<TKey> comparer)
        {
            if (source == null)
                throw new ArgumentNullException(nameof(source));
            if (keySelector == null)
                throw new ArgumentNullException(nameof(keySelector));
            if (elementSelector == null)
                throw new ArgumentNullException(nameof(elementSelector));
            if (capacity < 0)
                throw new ArgumentOutOfRangeException(nameof(capacity));
            if (comparer == null)

View on GitHub (pinned to 94b5d5ab91)