{"record":{"id":"8d7ab099cf54e6ca","repo":"dotnet/reactive","slug":"specified-argument-was-out-of-the-range-of-valid-values-8d7ab0","errorCode":null,"errorMessage":"Specified argument was out of the range of valid values. (Parameter 'capacity')","messagePattern":"Specified argument was out of the range of valid values\\. \\(Parameter 'capacity'\\)","errorType":"validation","errorClass":"ArgumentOutOfRangeException","httpStatus":null,"severity":"error","filePath":"AsyncRx.NET/System.Reactive.Async/Linq/Operators/GroupByUntil.cs","lineNumber":57,"sourceCode":"            if (comparer == null)\n                throw new ArgumentNullException(nameof(comparer));\n\n            return CreateAsyncObservable<IGroupedAsyncObservable<TKey, TSource>>.From(\n                source,\n                (keySelector, durationSelector, comparer),\n                static (source, state, observer) => GroupByUntilCore<TSource, TKey, TSource, TDuration>(source, observer, (o, d) => AsyncObserver.GroupByUntil(o, d, state.keySelector, state.durationSelector, state.comparer)));\n        }\n\n        public static IAsyncObservable<IGroupedAsyncObservable<TKey, TSource>> GroupByUntil<TSource, TKey, TDuration>(this IAsyncObservable<TSource> source, Func<TSource, TKey> keySelector, Func<IGroupedAsyncObservable<TKey, TSource>, IAsyncObservable<TDuration>> durationSelector, int capacity)\n        {\n            if (source == null)\n                throw new ArgumentNullException(nameof(source));\n            if (keySelector == null)\n                throw new ArgumentNullException(nameof(keySelector));\n            if (durationSelector == null)\n                throw new ArgumentNullException(nameof(durationSelector));\n            if (capacity < 0)\n                throw new ArgumentOutOfRangeException(nameof(capacity));\n\n            return CreateAsyncObservable<IGroupedAsyncObservable<TKey, TSource>>.From(\n                source,\n                (keySelector, durationSelector, capacity),\n                static (source, state, observer) => GroupByUntilCore<TSource, TKey, TSource, TDuration>(source, observer, (o, d) => AsyncObserver.GroupByUntil(o, d, state.keySelector, state.durationSelector, state.capacity)));\n        }\n\n        public static IAsyncObservable<IGroupedAsyncObservable<TKey, TSource>> GroupByUntil<TSource, TKey, TDuration>(this IAsyncObservable<TSource> source, Func<TSource, TKey> keySelector, Func<IGroupedAsyncObservable<TKey, TSource>, IAsyncObservable<TDuration>> durationSelector, int capacity, IEqualityComparer<TKey> comparer)\n        {\n            if (source == null)\n                throw new ArgumentNullException(nameof(source));\n            if (keySelector == null)\n                throw new ArgumentNullException(nameof(keySelector));\n            if (durationSelector == null)\n                throw new ArgumentNullException(nameof(durationSelector));\n            if (capacity < 0)\n                throw new ArgumentOutOfRangeException(nameof(capacity));\n            if (comparer == null)","sourceCodeStart":39,"sourceCodeEnd":75,"githubUrl":"https://github.com/dotnet/reactive/blob/94b5d5ab912789f5abe9a72138a25bbd716fe59c/AsyncRx.NET/System.Reactive.Async/Linq/Operators/GroupByUntil.cs#L39-L75","documentation":"The capacity parameter bounds how many groups may exist concurrently and must be non-negative. Passing a negative value throws ArgumentOutOfRangeException at GroupByUntil.cs:57. This is a fail-fast range check applied when the capacity overload is invoked.","triggerScenarios":"Calling AsyncObservable.GroupByUntil(source, keySelector, durationSelector, -1) — typically a computed capacity like limit - consumed that went negative, or an uninitialized/default-initialized sentinel.","commonSituations":"Capacity derived from configuration where a negative or unparsed value slipped in; arithmetic like expectedCount - actualCount producing -1; int fields defaulted to -1 as 'unset'.","solutions":["Clamp the capacity before the call: Math.Max(0, computedCapacity)","Fix the config/arithmetic source producing the negative value","Validate user- or config-supplied capacity at load time and reject negatives early"],"exampleFix":"// before\nint capacity = config.MaxGroups - activeGroups; // can be negative\nvar groups = source.GroupByUntil(x => x.Key, g => g.Take(1), capacity);\n// after\nint capacity = Math.Max(0, config.MaxGroups - activeGroups);\nvar groups = source.GroupByUntil(x => x.Key, g => g.Take(1), capacity);","handlingStrategy":"validation","validationCode":"if (capacity < 0) throw new ArgumentException(\"capacity must be >= 0\"); // or clamp: capacity = Math.Max(0, capacity);","typeGuard":"bool IsValidCapacity(int capacity) => capacity >= 0;","tryCatchPattern":"try { var groups = source.GroupByUntil(ks, ds, capacity); } catch (ArgumentOutOfRangeException ex) when (ex.ParamName == \"capacity\") { capacity = 0; /* retry or log bad config */ }","preventionTips":["Clamp computed capacities with Math.Max(0, n)","Validate capacity-bearing configuration at startup, not at call time","Avoid -1 sentinels for 'unset' int fields feeding API arguments"],"tags":["argument-out-of-range","async-rx","validation","capacity"],"backgroundTag":"argument-out-of-range","analyzedSha":"94b5d5ab912789f5abe9a72138a25bbd716fe59c","analyzedAt":"2026-09-15T02:26:24.759Z","contentChangedAt":"2026-09-15T02:26:24.759Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}