{"record":{"id":"8d5c6f3877a0c402","repo":"dotnet/reactive","slug":"value-cannot-be-null-parameter-observer-asyncobservablebase","errorCode":null,"errorMessage":"Value cannot be null. (Parameter 'observer')","messagePattern":"Value cannot be null\\. \\(Parameter 'observer'\\)","errorType":"validation","errorClass":"ArgumentNullException","httpStatus":null,"severity":"error","filePath":"AsyncRx.NET/System.Reactive.Async/AsyncObservableBase.cs","lineNumber":14,"sourceCode":"﻿// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT License.\n// See the LICENSE file in the project root for more information. \n\nusing System.Threading.Tasks;\n\nnamespace System.Reactive\n{\n    public abstract class AsyncObservableBase<T> : IAsyncObservable<T>\n    {\n        public async ValueTask<IAsyncDisposable> SubscribeAsync(IAsyncObserver<T> observer)\n        {\n            if (observer == null)\n                throw new ArgumentNullException(nameof(observer));\n\n            var autoDetach = new AutoDetachAsyncObserver(observer);\n\n            var subscription = await SubscribeAsyncCore(autoDetach).ConfigureAwait(false);\n\n            await autoDetach.AssignAsync(subscription).ConfigureAwait(false);\n\n            return autoDetach;\n        }\n\n        protected abstract ValueTask<IAsyncDisposable> SubscribeAsyncCore(IAsyncObserver<T> observer);\n\n        private sealed class AutoDetachAsyncObserver : AsyncObserverBase<T>, IAsyncDisposable\n        {\n            private readonly IAsyncObserver<T> _observer;\n            private readonly object _gate = new();\n\n            private IAsyncDisposable _subscription;","sourceCodeStart":1,"sourceCodeEnd":32,"githubUrl":"https://github.com/dotnet/reactive/blob/94b5d5ab912789f5abe9a72138a25bbd716fe59c/AsyncRx.NET/System.Reactive.Async/AsyncObservableBase.cs#L1-L32","documentation":"The comparer-overload of ToLookup validates all delegates up front. A null keySelector makes grouping impossible, so ArgumentNullException(nameof(keySelector)) is thrown immediately when composing the operator, before any elements flow.","triggerScenarios":"Calling AsyncObservable.ToLookup(observer, null, valueSelector, comparer) — 4-argument overload at ToLookup.cs:136 (the 3-argument overload's keySelector guard hits the same pattern at line 122).","commonSituations":"Key selector built from a lookup table or configuration map that was null; refactoring renamed a method leaving a null Func; generic helper forwarding a null selector.","solutions":["Supply a non-null Func<TSource,ValueTask<TKey>> or Func<TSource,TKey> key selector","Assert the key selector is resolved (e.g. from config/DI) before composing the pipeline","Default to an identity selector x => x when grouping by the element itself"],"exampleFix":"// before\nvar op = AsyncObservable.ToLookup(sink, (Func<Order, int>)null, x => x.Name, comparer);\n// after\nvar op = AsyncObservable.ToLookup(sink, x => x.CustomerId, x => x.Name, comparer);","handlingStrategy":"validation","validationCode":"if (observer is null || keySelector is null) throw new ArgumentException(\"observer and keySelector are required\");\nvar op = AsyncObservable.ToLookup(observer, keySelector, valueSelector, comparer);","typeGuard":"static bool CanGroup<TSource,TKey>(Func<TSource,ValueTask<TKey>> keySelector) => keySelector != null;","tryCatchPattern":"try\n{\n    var op = AsyncObservable.ToLookup(observer, keySelector, valueSelector, comparer);\n}\ncatch (ArgumentNullException ex) when (ex.ParamName == \"keySelector\")\n{\n    keySelector = x => new ValueTask<TKey>(DefaultKey(x)); // fallback key\n}","preventionTips":["Resolve key selectors from config/DI eagerly and assert non-null","Use method groups (x => x.CustomerId) rather than nullable delegate fields","Unit-test operator composition with all delegate arguments supplied"],"tags":["argument-null","key-selector","linq-operator"],"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"}