{"record":{"id":"9b0fe0c29c2dad2f","repo":"dotnet/reactive","slug":"nameof-witness","errorCode":null,"errorMessage":"nameof(witness)","messagePattern":"nameof\\(witness\\)","errorType":"exception","errorClass":"ArgumentNullException","httpStatus":null,"severity":"error","filePath":"AsyncRx.NET/System.Reactive.Async/Linq/Operators/Do.cs","lineNumber":254,"sourceCode":"        {\n            if (observer == null)\n                throw new ArgumentNullException(nameof(observer));\n            if (onNext == null)\n                throw new ArgumentNullException(nameof(onNext));\n            if (onError == null)\n                throw new ArgumentNullException(nameof(onError));\n            if (onCompleted == null)\n                throw new ArgumentNullException(nameof(onCompleted));\n\n            return Do(observer, Create(onNext, onError, onCompleted));\n        }\n\n        public static IAsyncObserver<TSource> Do<TSource>(IAsyncObserver<TSource> observer, IObserver<TSource> witness)\n        {\n            if (observer == null)\n                throw new ArgumentNullException(nameof(observer));\n            if (witness == null)\n                throw new ArgumentNullException(nameof(witness));\n\n            return Create<TSource>(\n                async x =>\n                {\n                    try\n                    {\n                        witness.OnNext(x);\n                    }\n                    catch (Exception ex)\n                    {\n                        await observer.OnErrorAsync(ex).ConfigureAwait(false);\n                        return;\n                    }\n\n                    await observer.OnNextAsync(x).ConfigureAwait(false);\n                },\n                async error =>\n                {","sourceCodeStart":236,"sourceCodeEnd":272,"githubUrl":"https://github.com/dotnet/reactive/blob/94b5d5ab912789f5abe9a72138a25bbd716fe59c/AsyncRx.NET/System.Reactive.Async/Linq/Operators/Do.cs#L236-L272","documentation":"In the witness-based Do overload, the IObserver<TSource> witness receives copies of the pipeline's notifications and must be non-null. The library throws ArgumentNullException for witness (Do.cs:254) if it is null, because there would be no side-effect observer to invoke. Validation occurs before any subscription work.","triggerScenarios":"Calling Do<TSource>(observer, witness) with a null witness, e.g. a side-effect logger or monitoring observer that was never constructed or that a factory returned as null.","commonSituations":"Optional diagnostics observer resolved from DI/config is null in environments without monitoring enabled; test scaffolding that passes null instead of a stub observer; conditional instrumentation code that ends up passing nothing.","solutions":["Pass a real witness observer; if diagnostics are optional, pass a no-op Observer stub instead of null.","Skip the Do call entirely when no witness is available (condition the pipeline construction).","Fix the factory/DI registration that was supposed to produce the witness observer."],"exampleFix":"// before\nvar decorated = Do(src, diagnosticsObserver); // null when monitoring disabled\n// after\nvar decorated = diagnosticsObserver != null ? Do(src, diagnosticsObserver) : src;","handlingStrategy":"fallback","validationCode":"var decorated = witness != null ? Do(observer, witness) : observer; // skip witness when unavailable","typeGuard":"static bool HasWitness<TSource>(IObserver<TSource>? w) => w is not null;","tryCatchPattern":"try\n{\n    var decorated = Do(observer, witness);\n}\ncatch (ArgumentNullException ex) when (ex.ParamName == \"witness\")\n{\n    logger.LogWarning(\"No witness observer available; skipping Do side-effects\");\n    var decorated = observer;\n}","preventionTips":["Make the witness an explicit no-op stub rather than null when diagnostics are disabled.","Register a default observer in DI so resolution never yields null.","Conditionally compose the Do step instead of passing a nullable witness."],"tags":["argument-null","rx","do-operator","observer","csharp"],"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"}