{"record":{"id":"262eaca775d7880d","repo":"dotnet/reactive","slug":"value-cannot-be-null-parameter-observer-switch","errorCode":null,"errorMessage":"Value cannot be null. (Parameter 'observer')","messagePattern":"Value cannot be null\\. \\(Parameter 'observer'\\)","errorType":"exception","errorClass":"ArgumentNullException","httpStatus":null,"severity":"error","filePath":"AsyncRx.NET/System.Reactive.Async/Linq/Operators/Switch.cs","lineNumber":35,"sourceCode":"            return Create<IAsyncObservable<TSource>, TSource>(\n                source,\n                async static (source, observer) =>\n                {\n                    var (sink, cancel) = AsyncObserver.Switch(observer);\n\n                    var subscription = await source.SubscribeSafeAsync(sink).ConfigureAwait(false);\n\n                    return StableCompositeAsyncDisposable.Create(subscription, cancel);\n                });\n        }\n    }\n\n    public partial class AsyncObserver\n    {\n        public static (IAsyncObserver<IAsyncObservable<TSource>>, IAsyncDisposable) Switch<TSource>(IAsyncObserver<TSource> observer)\n        {\n            if (observer == null)\n                throw new ArgumentNullException(nameof(observer));\n\n            var gate = new AsyncGate();\n\n            var isStopped = false;\n            var hasLatest = false;\n            var latest = 0UL;\n\n            var disposable = new SerialAsyncDisposable();\n\n            return\n                (\n                    Create<IAsyncObservable<TSource>>(\n                        async xs =>\n                        {\n                            ulong id;\n\n                            using (await gate.LockAsync().ConfigureAwait(false))\n                            {","sourceCodeStart":17,"sourceCodeEnd":53,"githubUrl":"https://github.com/dotnet/reactive/blob/94b5d5ab912789f5abe9a72138a25bbd716fe59c/AsyncRx.NET/System.Reactive.Async/Linq/Operators/Switch.cs#L17-L53","documentation":"AsyncObserver.Switch is the low-level sink factory for the Switch operator and validates that the downstream observer is non-null, throwing ArgumentNullException at Switch.cs:35. It guards the state machine (gate, hasLatest, latest tracking) that would otherwise capture a null observer and fail on the first OnNextAsync notification.","triggerScenarios":"Calling AsyncObserver.Switch<TSource>(null) directly, or a custom Create(...) composition that passes a null observer into AsyncObserver.Switch.","commonSituations":"Writing custom operators on top of AsyncObserver primitives where the observer parameter flows through unvalidated; unit tests passing null to exercise guard clauses.","solutions":["Pass a valid IAsyncObserver<TSource> obtained from your subscription context","If writing a custom operator, validate the observer yourself before delegating to AsyncObserver.Switch","Prefer the public source.Switch() extension, which wires up a real observer automatically"],"exampleFix":"// before\nvar (sink, cancel) = AsyncObserver.Switch<TSource>(observer); // observer may be null\n// after\nif (observer == null) throw new ArgumentNullException(nameof(observer));\nvar (sink, cancel) = AsyncObserver.Switch<TSource>(observer);","handlingStrategy":"validation","validationCode":"if (observer is null)\n    throw new ArgumentNullException(nameof(observer));\nvar (sink, cancel) = AsyncObserver.Switch(observer);","typeGuard":"static bool HasObserver<T>(IAsyncObserver<T>? o) => o is not null;","tryCatchPattern":"try\n{\n    var (sink, cancel) = AsyncObserver.Switch(observer);\n}\ncatch (ArgumentNullException ex) when (ex.ParamName == \"observer\")\n{\n    // custom-operator wiring bug: the downstream observer was never supplied\n    logger.LogError(ex, \"AsyncObserver.Switch requires a non-null observer\");\n}","preventionTips":["When writing custom operators, validate observer parameters before delegating to AsyncObserver.* primitives","Prefer public extension operators (source.Switch()) over hand-wiring AsyncObserver sinks","Keep observer arguments non-nullable in your own signatures to surface bugs at compile time"],"tags":["argumentnull","async-rx","observer","switch"],"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"}