{"record":{"id":"91d28d8074a6df20","repo":"dotnet/reactive","slug":"capacity-groupbyuntil","errorCode":null,"errorMessage":"capacity","messagePattern":"capacity","errorType":"validation","errorClass":"ArgumentOutOfRangeException","httpStatus":null,"severity":"error","filePath":"AsyncRx.NET/System.Reactive.Async/Linq/Operators/GroupByUntil.cs","lineNumber":201,"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, ValueTask<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, ValueTask<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":183,"sourceCodeEnd":219,"githubUrl":"https://github.com/dotnet/reactive/blob/94b5d5ab912789f5abe9a72138a25bbd716fe59c/AsyncRx.NET/System.Reactive.Async/Linq/Operators/GroupByUntil.cs#L183-L219","documentation":"This ArgumentOutOfRangeException is thrown synchronously when the capacity argument is negative. capacity sizes the internal dictionary of concurrently open groups, so a negative value is meaningless and rejected before any subscription occurs.","triggerScenarios":"Calling a capacity-taking GroupByUntil overload with capacity < 0, e.g. source.GroupByUntil(keySelector, durationSelector, -1) or a capacity value computed from user input or configuration that resolved to a negative number.","commonSituations":"Reading a capacity from config with a sign/datatype mistake; arithmetic like maxCount - expected producing -1 when the collection is empty; misunderstanding that 0 is allowed but negative is not.","solutions":["Pass a non-negative capacity (0 or greater).","Clamp computed values before the call: capacity = Math.Max(0, computedCapacity).","Validate configuration-sourced capacity at startup and fail fast with a clear message."],"exampleFix":"// before\nvar grouped = source.GroupByUntil(ks, ds, config.MaxGroups - config.UsedGroups);\n// after\nvar capacity = Math.Max(0, config.MaxGroups - config.UsedGroups);\nvar grouped = source.GroupByUntil(ks, ds, capacity);","handlingStrategy":"validation","validationCode":"if (capacity < 0)\n    throw new ArgumentOutOfRangeException(nameof(capacity), \"Capacity must be non-negative.\");\nvar grouped = source.GroupByUntil(ks, ds, capacity);","typeGuard":"static bool IsValidCapacity(int capacity) => capacity >= 0;","tryCatchPattern":"try\n{\n    var grouped = source.GroupByUntil(ks, ds, capacity);\n}\ncatch (ArgumentOutOfRangeException ex) when (ex.ParamName == \"capacity\")\n{\n    capacity = 0; // or log and retry with a valid capacity\n    var grouped = source.GroupByUntil(ks, ds, capacity);\n}","preventionTips":["Clamp any computed capacity with Math.Max(0, value).","Validate config values for capacity at startup.","Remember 0 is legal; only negatives throw."],"tags":["argument-out-of-range","capacity","async-reactive"],"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"}