{"record":{"id":"93fd7a8287e2d52f","repo":"dotnet/reactive","slug":"value-cannot-be-null-parameter-invokehandler","errorCode":null,"errorMessage":"Value cannot be null. (Parameter 'invokeHandler')","messagePattern":"Value cannot be null\\. \\(Parameter 'invokeHandler'\\)","errorType":"exception","errorClass":"ArgumentNullException","httpStatus":null,"severity":"error","filePath":"AsyncRx.NET/System.Reactive.Async/Internal/EventPatternSourceBaseInternal.cs","lineNumber":37,"sourceCode":"    /// avoid a conflict. Work out whether we could in fact just use the type defined in System.Reactive. It's not identical,\n    /// but perhaps it offers what we need.\n    /// </remarks>\n    internal abstract class EventPatternSourceBaseInternal<TSender, TEventArgs>\n    {\n        private readonly IAsyncObservable<EventPattern<TSender, TEventArgs>> _source;\n        private readonly Dictionary<Delegate, Stack<IAsyncDisposable>> _subscriptions;\n        private readonly Action<Action<TSender, TEventArgs>, /*object,*/ EventPattern<TSender, TEventArgs>> _invokeHandler;\n\n        /// <summary>\n        /// Creates a new event pattern source.\n        /// </summary>\n        /// <param name=\"source\">Source sequence to expose as an event.</param>\n        /// <param name=\"invokeHandler\">Delegate used to invoke the event for each element of the sequence.</param>\n        /// <exception cref=\"ArgumentNullException\"><paramref name=\"source\"/> or <paramref name=\"invokeHandler\"/> is null.</exception>\n        protected EventPatternSourceBaseInternal(IAsyncObservable<EventPattern<TSender, TEventArgs>> source, Action<Action<TSender, TEventArgs>, /*object,*/ EventPattern<TSender, TEventArgs>> invokeHandler)\n        {\n            _source = source ?? throw new ArgumentNullException(nameof(source));\n            _invokeHandler = invokeHandler ?? throw new ArgumentNullException(nameof(invokeHandler));\n            _subscriptions = new Dictionary<Delegate, Stack<IAsyncDisposable>>();\n        }\n\n        /// <summary>\n        /// Adds the specified event handler, causing a subscription to the underlying source.\n        /// </summary>\n        /// <param name=\"handler\">Event handler to add. The same delegate should be passed to the Remove operation in order to remove the event handler.</param>\n        /// <param name=\"invoke\">Invocation delegate to raise the event in the derived class.</param>\n        /// <exception cref=\"ArgumentNullException\"><paramref name=\"handler\"/> or <paramref name=\"invoke\"/> is null.</exception>\n        protected void Add(Delegate handler, Action<TSender, TEventArgs> invoke)\n        {\n            if (handler == null)\n                throw new ArgumentNullException(nameof(handler));\n            if (invoke == null)\n                throw new ArgumentNullException(nameof(invoke));\n\n            var gate = new object();\n            var isAdded = false;","sourceCodeStart":19,"sourceCodeEnd":55,"githubUrl":"https://github.com/dotnet/reactive/blob/94b5d5ab912789f5abe9a72138a25bbd716fe59c/AsyncRx.NET/System.Reactive.Async/Internal/EventPatternSourceBaseInternal.cs#L19-L55","documentation":"The EventPatternSourceBaseInternal constructor requires a non-null invokeHandler delegate, used to raise the event for each element of the sequence. A null delegate is rejected with ArgumentNullException at construction, matching the constructor's documented exception.","triggerScenarios":"Deriving from EventPatternSourceBaseInternal and passing null (or an uninitialized method-group/field delegate) as the invokeHandler constructor argument.","commonSituations":"Passing a delegate field assigned only later in initialization (null at base-constructor time); refactor renamed the target method so the method group no longer resolves and someone replaced it with null; conditional delegate selection yielding null.","solutions":["Pass a valid Action<Action<TSender,TEventArgs>, EventPattern<TSender,TEventArgs>> delegate.","Initialize the handler delegate before calling the base constructor.","Throw a descriptive error or provide a no-op delegate if invocation is legitimately absent."],"exampleFix":"// before\nprotected MySource(Func<Action<Handler> > lazy)\n    : base(source, lazy?.Handler) { } // null until initialized\n// after\nprotected MySource(IAsyncObservable<EventPattern<object, EventArgs>> source)\n    : base(source, (h, e) => Handler(h, e)) { }","handlingStrategy":"validation","validationCode":"if (invokeHandler is null) throw new ArgumentNullException(nameof(invokeHandler));\n// then call the base constructor with invokeHandler","typeGuard":"static bool HasInvokeHandler(Action<Action<TSender,TEventArgs>, EventPattern<TSender,TEventArgs>>? h) => h is not null;","tryCatchPattern":"try { CreateEventPatternSource(source, invokeHandler); }\ncatch (ArgumentNullException ex) when (ex.ParamName == \"invokeHandler\")\n{ log.LogError(\"invokeHandler delegate was null\"); }","preventionTips":["Assign invocation delegates before the base constructor runs (pass method groups, not fields assigned later).","Avoid conditional expressions that can yield null for the handler.","Keep delegate creation inline in the constructor call."],"tags":["argument-null","event-pattern","delegate"],"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"}