{"record":{"id":"aa49babf7d1740b2","repo":"dotnet/reactive","slug":"value-cannot-be-null-parameter-subscription","errorCode":null,"errorMessage":"Value cannot be null. (Parameter 'subscription')","messagePattern":"Value cannot be null\\. \\(Parameter 'subscription'\\)","errorType":"validation","errorClass":"ArgumentNullException","httpStatus":null,"severity":"error","filePath":"AsyncRx.NET/System.Reactive.Async/Linq/Operators/GroupBy.cs","lineNumber":290,"sourceCode":"            var d = new SingleAssignmentAsyncDisposable();\n\n            var (sink, subscription) = createObserver(observer, d);\n\n            var inner = await source.SubscribeSafeAsync(sink).ConfigureAwait(false);\n            await d.AssignAsync(inner).ConfigureAwait(false);\n\n            return subscription;\n        }\n    }\n\n    public partial class AsyncObserver\n    {\n        public static (IAsyncObserver<TSource>, IAsyncDisposable) GroupBy<TSource, TKey>(IAsyncObserver<IGroupedAsyncObservable<TKey, TSource>> observer, IAsyncDisposable subscription, Func<TSource, TKey> keySelector)\n        {\n            if (observer == null)\n                throw new ArgumentNullException(nameof(observer));\n            if (subscription == null)\n                throw new ArgumentNullException(nameof(subscription));\n            if (keySelector == null)\n                throw new ArgumentNullException(nameof(keySelector));\n\n            return GroupBy(observer, subscription, keySelector, int.MaxValue, EqualityComparer<TKey>.Default);\n        }\n\n        public static (IAsyncObserver<TSource>, IAsyncDisposable) GroupBy<TSource, TKey>(IAsyncObserver<IGroupedAsyncObservable<TKey, TSource>> observer, IAsyncDisposable subscription, Func<TSource, TKey> keySelector, IEqualityComparer<TKey> comparer)\n        {\n            if (observer == null)\n                throw new ArgumentNullException(nameof(observer));\n            if (subscription == null)\n                throw new ArgumentNullException(nameof(subscription));\n            if (keySelector == null)\n                throw new ArgumentNullException(nameof(keySelector));\n            if (comparer == null)\n                throw new ArgumentNullException(nameof(comparer));\n\n            return GroupBy(observer, subscription, keySelector, int.MaxValue, comparer);","sourceCodeStart":272,"sourceCodeEnd":308,"githubUrl":"https://github.com/dotnet/reactive/blob/94b5d5ab912789f5abe9a72138a25bbd716fe59c/AsyncRx.NET/System.Reactive.Async/Linq/Operators/GroupBy.cs#L272-L308","documentation":"AsyncObserver.GroupBy requires the IAsyncDisposable representing the upstream subscription so groups can be disposed when the pipeline terminates; a null subscription is rejected with ArgumentNullException. This guard sits in the simplest observer-level overload (observer, subscription, keySelector).","triggerScenarios":"Calling AsyncObserver.GroupBy(observer, subscription, keySelector) with subscription == null, typically when wiring the observer tuple manually.","commonSituations":"Custom operator code forgets to thread the subscription disposable through; a helper caches the observer but not the subscription; refactor dropped the subscription argument.","solutions":["Pass the subscription IAsyncDisposable supplied by the CreateAsyncObservable callback.","If no disposal is needed, provide a no-op disposable (e.g. AsyncDisposable.Nop / DefaultAsyncDisposable) rather than null.","Add a null guard with a clear message in the custom operator before delegating."],"exampleFix":"// before\nreturn AsyncObserver.GroupBy(observer, null, keySelector);\n// after\nreturn AsyncObserver.GroupBy(observer, subscription ?? AsyncDisposable.Nop, keySelector);","handlingStrategy":"validation","validationCode":"subscription ??= AsyncDisposable.Nop;\nvar (o, d) = AsyncObserver.GroupBy(observer, subscription, keySelector);","typeGuard":"bool HasSubscription(IAsyncDisposable? s) => s is not null;","tryCatchPattern":"try\n{\n    var (o, d) = AsyncObserver.GroupBy(observer, subscription, keySelector);\n}\ncatch (ArgumentNullException ex) when (ex.ParamName == \"subscription\")\n{\n    var (o, d) = AsyncObserver.GroupBy(observer, AsyncDisposable.Nop, keySelector);\n}","preventionTips":["Always propagate the disposable returned alongside the observer from operator callbacks.","Pair observer and subscription in a single record/struct so they travel together.","Never dispose-and-null the subscription before passing it to the factory."],"tags":["argument-null","subscription","asyncobserver","asyncrx"],"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"}