{"record":{"id":"7dd6c1a818a141ff","repo":"dotnet/reactive","slug":"argumentnullexception-comparer","errorCode":null,"errorMessage":"ArgumentNullException: comparer","messagePattern":"ArgumentNullException: comparer","errorType":"validation","errorClass":"ArgumentNullException","httpStatus":null,"severity":"error","filePath":"AsyncRx.NET/System.Reactive.Async/Linq/Operators/GroupBy.cs","lineNumber":66,"sourceCode":"            if (capacity < 0)\n                throw new ArgumentOutOfRangeException(nameof(capacity));\n\n            return CreateAsyncObservable<IGroupedAsyncObservable<TKey, TSource>>.From(\n                source,\n                (keySelector, capacity),\n                static (source, state, observer) => GroupByCore(source, observer, (o, d) => AsyncObserver.GroupBy(o, d, state.keySelector, state.capacity)));\n        }\n\n        public static IAsyncObservable<IGroupedAsyncObservable<TKey, TSource>> GroupBy<TSource, TKey>(this IAsyncObservable<TSource> source, Func<TSource, TKey> keySelector, 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 (capacity < 0)\n                throw new ArgumentOutOfRangeException(nameof(capacity));\n            if (comparer == null)\n                throw new ArgumentNullException(nameof(comparer));\n\n            return CreateAsyncObservable<IGroupedAsyncObservable<TKey, TSource>>.From(\n                source,\n                (keySelector, capacity, comparer),\n                static (source, state, observer) => GroupByCore(source, observer, (o, d) => AsyncObserver.GroupBy(o, d, state.keySelector, state.capacity, state.comparer)));\n        }\n\n        public static IAsyncObservable<IGroupedAsyncObservable<TKey, TElement>> GroupBy<TSource, TKey, TElement>(this IAsyncObservable<TSource> source, Func<TSource, TKey> keySelector, Func<TSource, TElement> elementSelector)\n        {\n            if (source == null)\n                throw new ArgumentNullException(nameof(source));\n            if (keySelector == null)\n                throw new ArgumentNullException(nameof(keySelector));\n            if (elementSelector == null)\n                throw new ArgumentNullException(nameof(elementSelector));\n\n            return CreateAsyncObservable<IGroupedAsyncObservable<TKey, TElement>>.From(\n                source,","sourceCodeStart":48,"sourceCodeEnd":84,"githubUrl":"https://github.com/dotnet/reactive/blob/94b5d5ab912789f5abe9a72138a25bbd716fe59c/AsyncRx.NET/System.Reactive.Async/Linq/Operators/GroupBy.cs#L48-L84","documentation":"GroupBy(source, keySelector, capacity, comparer) throws ArgumentNullException when comparer is null. A non-null IEqualityComparer<TKey> is mandatory in this overload; there is no implicit default-comparer fallback. Validation happens last in the argument-check sequence but still before any asynchronous work.","triggerScenarios":"Calling GroupBy(source, keySelector, capacity, null) — comparer from DI/config resolution returning null, or a variable that was conditionally assigned.","commonSituations":"Missing DI registration for a custom comparer; comparer lookup by type name failing; conditional comparer selection with a branch that leaves it null.","solutions":["Pass a non-null comparer; use EqualityComparer<TKey>.Default for default semantics.","Fix the comparer factory/DI registration so it returns an instance.","Coalesce with comparer ?? EqualityComparer<TKey>.Default at the call site."],"exampleFix":"// before\nvar groups = source.GroupBy(x => x.Key, 16, container.GetService<IEqualityComparer<Key>>()); // may be null\n// after\nvar groups = source.GroupBy(x => x.Key, 16, container.GetService<IEqualityComparer<Key>>() ?? EqualityComparer<Key>.Default);","handlingStrategy":"validation","validationCode":"if (comparer is null) comparer = EqualityComparer<TKey>.Default;","typeGuard":"static bool HasComparer<TKey>(IEqualityComparer<TKey> c) => c is not null;","tryCatchPattern":"try { var groups = source.GroupBy(keySelector, capacity, comparer); }\ncatch (ArgumentNullException ex) when (ex.ParamName == \"comparer\") { log.LogError(ex, \"GroupBy comparer was null\"); throw; }","preventionTips":["Always coalesce resolved comparers with EqualityComparer<TKey>.Default.","Assert comparer registrations exist before resolving from DI.","Wrap comparer resolution in a helper that never returns null."],"tags":["null-argument","linq","argument-validation"],"backgroundTag":"null-argument","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"}