{"record":{"id":"9050d25f45eb1041","repo":"dotnet/reactive","slug":"value-cannot-be-null-parameter-source-switch","errorCode":null,"errorMessage":"Value cannot be null. (Parameter 'source')","messagePattern":"Value cannot be null\\. \\(Parameter 'source'\\)","errorType":"exception","errorClass":"ArgumentNullException","httpStatus":null,"severity":"error","filePath":"AsyncRx.NET/System.Reactive.Async/Linq/Operators/Switch.cs","lineNumber":15,"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.Reactive.Disposables;\nusing System.Threading;\n\nnamespace System.Reactive.Linq\n{\n    public partial class AsyncObservable\n    {\n        public static IAsyncObservable<TSource> Switch<TSource>(this IAsyncObservable<IAsyncObservable<TSource>> source)\n        {\n            if (source == null)\n                throw new ArgumentNullException(nameof(source));\n\n            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        {","sourceCodeStart":1,"sourceCodeEnd":33,"githubUrl":"https://github.com/dotnet/reactive/blob/94b5d5ab912789f5abe9a72138a25bbd716fe59c/AsyncRx.NET/System.Reactive.Async/Linq/Operators/Switch.cs#L1-L33","documentation":"The Switch extension operator requires a non-null source observable of inner observables. It throws ArgumentNullException at composition time (Switch.cs:15) so that a null source fails immediately at the call site rather than surfacing as a NullReferenceException deep inside SubscribeAsync. This is standard defensive validation across all AsyncRx operators.","triggerScenarios":"Calling source.Switch() where source is a null IAsyncObservable<IAsyncObservable<T>>, e.g. a factory method or dictionary lookup that returned null before being chained with .Switch().","commonSituations":"Chaining Switch onto the result of another operator or a memoized cache entry that is null; refactoring where an observable field was renamed or not yet assigned; conditional pipeline construction where a branch forgot to assign the source.","solutions":["Verify the outer observable is non-null before invoking .Switch()","Check any factory/cache lookup that produced the source and handle its null return before chaining","Add a null check or throw a descriptive exception at the pipeline construction site","Restructure so the inner observables are produced by a non-null source (e.g. Select over an existing sequence)"],"exampleFix":"// before\nvar merged = maybeSource.Switch(); // NRE/ANRE when maybeSource is null\n// after\nif (maybeSource == null) throw new InvalidOperationException(\"inner source not initialized\");\nvar merged = maybeSource.Switch();","handlingStrategy":"validation","validationCode":"if (source is null)\n    throw new InvalidOperationException(\"Switch requires a non-null source of inner observables.\");\nvar merged = source.Switch();","typeGuard":"static bool HasSource<T>(IAsyncObservable<IAsyncObservable<T>>? s) => s is not null;","tryCatchPattern":"try\n{\n    var merged = source.Switch();\n}\ncatch (ArgumentNullException ex) when (ex.ParamName == \"source\")\n{\n    logger.LogError(ex, \"Switch called with null source; check the upstream factory/lookup\");\n}","preventionTips":["Check the null-ability of factory results before chaining extension operators","Use nullable reference type annotations so a null source is caught at compile time","Fail fast at pipeline construction with descriptive exceptions instead of letting guards fire","Avoid memoization patterns that can cache null results for observables"],"tags":["argumentnull","async-rx","operator","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"}