{"record":{"id":"624d9d6e2dd07125","repo":"dotnet/reactive","slug":"argumentnullexception-addhandler","errorCode":null,"errorMessage":"ArgumentNullException: addHandler","messagePattern":"ArgumentNullException: addHandler","errorType":"validation","errorClass":"ArgumentNullException","httpStatus":null,"severity":"error","filePath":"Rx.NET/Source/src/System.Reactive.WindowsRuntime/System.Reactive.Linq/WindowsObservable.Events.cs","lineNumber":33,"sourceCode":"    /// </summary>\n    [CLSCompliant(false)]\n    public static partial class WindowsObservable\n    {\n        /// <summary>\n        /// Converts a typed event, conforming to the standard event pattern, to an observable sequence.\n        /// </summary>\n        /// <typeparam name=\"TSender\">The type of the sender that raises the event.</typeparam>\n        /// <typeparam name=\"TResult\">The type of the event data generated by the event.</typeparam>\n        /// <param name=\"addHandler\">Action that attaches the given event handler to the underlying .NET event.</param>\n        /// <param name=\"removeHandler\">Action that detaches the given event handler from the underlying .NET event.</param>\n        /// <returns>The observable sequence that contains data representations of invocations of the underlying typed event.</returns>\n        /// <exception cref=\"ArgumentNullException\"><paramref name=\"addHandler\"/> or <paramref name=\"removeHandler\"/> is null.</exception>\n        /// <seealso cref=\"ToEventPattern\"/>\n        public static IObservable<EventPattern<TSender, TResult>> FromEventPattern<TSender, TResult>(Action<TypedEventHandler<TSender, TResult>> addHandler, Action<TypedEventHandler<TSender, TResult>> removeHandler)\n        {\n            if (addHandler == null)\n            {\n                throw new ArgumentNullException(nameof(addHandler));\n            }\n\n            if (removeHandler == null)\n            {\n                throw new ArgumentNullException(nameof(removeHandler));\n            }\n\n            return Observable.Create<EventPattern<TSender, TResult>>(observer =>\n            {\n                var h = new TypedEventHandler<TSender, TResult>((sender, args) =>\n                {\n                    observer.OnNext(new EventPattern<TSender, TResult>(sender, args));\n                });\n\n                addHandler(h);\n\n                return () =>\n                {","sourceCodeStart":15,"sourceCodeEnd":51,"githubUrl":"https://github.com/dotnet/reactive/blob/94b5d5ab912789f5abe9a72138a25bbd716fe59c/Rx.NET/Source/src/System.Reactive.WindowsRuntime/System.Reactive.Linq/WindowsObservable.Events.cs#L15-L51","documentation":"FromEventPattern<TSender, TResult>(Action<TypedEventHandler<TSender, TResult>> addHandler, Action<...> removeHandler) converts a WinRT event into an observable, and it throws ArgumentNullException(\"addHandler\") when the addHandler delegate is null. Both handler delegates are required: addHandler attaches the TypedEventHandler when the observable is subscribed.","triggerScenarios":"Calling Observable.FromEventPattern<TSender, TResult>(null, removeHandler) — passing a null add delegate, often from a variable resolved by reflection or string lookup that yielded null.","commonSituations":"Reflection-based event wiring where the add accessor name is misspelled or the event doesn't exist on the target type; generic wrappers storing add/remove delegates that weren't initialized; ported code where one of the two delegates was dropped.","solutions":["Pass real add/remove accessor method groups, e.g. (h => target.Event += h, h => target.Event -= h).","If wiring via reflection, verify GetAddMethod()/Delegate.CreateDelegate results are non-null before calling and throw a clearer error otherwise.","Check spelling/availability of the WinRT event on the actual runtime type; use the correct overload for non-TypedEventHandler events."],"exampleFix":"// before\nAction<TypedEventHandler<Button, object>> add = GetAdd(\"Click\"); // null: bad lookup\nObservable.FromEventPattern<Button, object>(add, remove);\n// after\nvar add = new Action<TypedEventHandler<Button, object>>(h => button.Click += h);\nvar remove = new Action<TypedEventHandler<Button, object>>(h => button.Click -= h);\nObservable.FromEventPattern<Button, object>(add, remove);","handlingStrategy":"validation","validationCode":"if (addHandler == null || removeHandler == null)\n    throw new InvalidOperationException(\"FromEventPattern requires both add and remove handlers\");","typeGuard":"bool ValidHandlers<TH>(Action<TH>? add, Action<TH>? remove) => add is not null && remove is not null;","tryCatchPattern":"try { obs = Observable.FromEventPattern<TSender, TResult>(add, remove); }\ncatch (ArgumentNullException ex) when (ex.ParamName == \"addHandler\") { log.Error(\"add accessor missing for event wiring\"); }","preventionTips":["Always use method-group/lambdas for +=/-= accessors rather than reflection-derived delegates","When using reflection, assert GetAddMethod/GetRemoveMethod results before calling Rx","Prefer the exact overload matching the event's delegate type (TypedEventHandler)"],"tags":["rx","null-argument","windows-runtime","events"],"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"}