{"record":{"id":"dad250ad09a76b2b","repo":"dotnet/reactive","slug":"nameof-source-finally","errorCode":null,"errorMessage":"nameof(source)","messagePattern":"nameof\\(source\\)","errorType":"exception","errorClass":"ArgumentNullException","httpStatus":null,"severity":"error","filePath":"AsyncRx.NET/System.Reactive.Async/Linq/Operators/Finally.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.Tasks;\n\nnamespace System.Reactive.Linq\n{\n    public partial class AsyncObservable\n    {\n        public static IAsyncObservable<TSource> Finally<TSource>(this IAsyncObservable<TSource> source, Action finallyAction)\n        {\n            if (source == null)\n                throw new ArgumentNullException(nameof(source));\n            if (finallyAction == null)\n                throw new ArgumentNullException(nameof(finallyAction));\n\n            return Create(\n                source,\n                finallyAction,\n                static async (source, finallyAction, observer) =>\n                {\n                    var subscription = await source.SubscribeSafeAsync(observer).ConfigureAwait(false);\n\n                    return AsyncDisposable.Create(async () =>\n                    {\n                        try\n                        {\n                            await subscription.DisposeAsync().ConfigureAwait(false);\n                        }\n                        finally\n                        {","sourceCodeStart":1,"sourceCodeEnd":33,"githubUrl":"https://github.com/dotnet/reactive/blob/94b5d5ab912789f5abe9a72138a25bbd716fe59c/AsyncRx.NET/System.Reactive.Async/Linq/Operators/Finally.cs#L1-L33","documentation":"This is an ArgumentNullException thrown by AsyncObservable.Finally when the source observable is null. Finally attaches a guaranteed-invoked Action after the source terminates, and composition requires a real source to subscribe to, so a null source fails immediately at the call site.","triggerScenarios":"Calling source.Finally(action) where source is null — e.g. chained off a method that returned null, a registry lookup that missed, or an expression evaluated on an uninitialized observable.","commonSituations":"Cleanup wiring around streams that may be absent; refactoring where the source factory became nullable; pipelines built from config where a source key was missing.","solutions":["Ensure the source observable is non-null before calling Finally","Fix the factory/lookup that returned null","Guard optional sources: source?.Finally(action) ?? emptyObservable, or check null explicitly"],"exampleFix":"// before\nvar tracked = source.Finally(() => Console.WriteLine(\"done\")); // source null\n// after\nvar tracked = source?.Finally(() => Console.WriteLine(\"done\")) ?? AsyncObservable.Empty<TSource>();","handlingStrategy":"validation","validationCode":"if (source is null) throw new ArgumentNullException(nameof(source));\nvar tracked = source.Finally(finallyAction);","typeGuard":"bool HasSource<TSource>(IAsyncObservable<TSource> s) => s is not null;","tryCatchPattern":"try { var tracked = source.Finally(finallyAction); }\ncatch (ArgumentNullException ex) when (ex.ParamName == \"source\") { /* substitute an empty observable or skip wiring */ }","preventionTips":["Ensure source-producing methods never return null; return Empty<TSource>() instead","Also validate finallyAction is non-null — Finally checks it too","Use source?.Finally(action) patterns for optional sources"],"tags":["argument-null","async-rx","observable"],"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"}