{"record":{"id":"af4834a86f9156df","repo":"dotnet/reactive","slug":"removehandler","errorCode":null,"errorMessage":"removeHandler","messagePattern":"removeHandler","errorType":"exception","errorClass":"ArgumentNullException","httpStatus":null,"severity":"error","filePath":"AsyncRx.NET/System.Reactive.Async/Linq/Operators/FromEvent.cs","lineNumber":19,"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.Concurrency;\nusing System.Reactive.Disposables;\nusing System.Threading;\nusing System.Threading.Tasks;\n\nnamespace System.Reactive.Linq\n{\n    public partial class AsyncObservable\n    {\n        public static IAsyncObservable<TEventArgs> FromEvent<TEventArgs>(Action<Action<TEventArgs>> addHandler, Action<Action<TEventArgs>> removeHandler)\n        {\n            if (addHandler == null)\n                throw new ArgumentNullException(nameof(addHandler));\n            if (removeHandler == null)\n                throw new ArgumentNullException(nameof(removeHandler));\n\n            return FromEventCore<Action<TEventArgs>, TEventArgs>(h => h, addHandler, removeHandler, GetSchedulerForCurrentContext());\n        }\n\n        public static IAsyncObservable<TEventArgs> FromEvent<TEventArgs>(Action<Action<TEventArgs>> addHandler, Action<Action<TEventArgs>> removeHandler, IAsyncScheduler scheduler)\n        {\n            if (addHandler == null)\n                throw new ArgumentNullException(nameof(addHandler));\n            if (removeHandler == null)\n                throw new ArgumentNullException(nameof(removeHandler));\n            if (scheduler == null)\n                throw new ArgumentNullException(nameof(scheduler));\n\n            return FromEventCore<Action<TEventArgs>, TEventArgs>(h => h, addHandler, removeHandler, scheduler);\n        }\n\n        public static IAsyncObservable<TEventArgs> FromEvent<TDelegate, TEventArgs>(Action<TDelegate> addHandler, Action<TDelegate> removeHandler)\n        {","sourceCodeStart":1,"sourceCodeEnd":37,"githubUrl":"https://github.com/dotnet/reactive/blob/94b5d5ab912789f5abe9a72138a25bbd716fe59c/AsyncRx.NET/System.Reactive.Async/Linq/Operators/FromEvent.cs#L1-L37","documentation":"FromEvent<TEventArgs>(addHandler, removeHandler) checks addHandler then removeHandler. This error is thrown when removeHandler is null (parameter name 'removeHandler'). removeHandler is essential for disposing the subscription and detaching the handler; the library refuses null to prevent event-handler leaks.","triggerScenarios":"Calling AsyncObservable.FromEvent<TEventArgs>(addHandler, removeHandler) with removeHandler == null; FromEvent.cs:19 is the `throw new ArgumentNullException(nameof(removeHandler))`.","commonSituations":"Only the subscription side implemented in a custom event wrapper; events declared with add-only accessors; copied code where the unsubscribe lambda was deleted during refactoring.","solutions":["Pass h => source.Event -= h as removeHandler.","Ensure the event has an accessible remove accessor (avoid add-only custom events).","Implement add and remove symmetrically in wrappers.","If unsubscribe is impossible, do not use FromEvent; adapt the source instead."],"exampleFix":"// before\nvar obs = AsyncObservable.FromEvent<EventArgs>(h => obj.MyEvent += h, null);\n// after\nvar obs = AsyncObservable.FromEvent<EventArgs>(h => obj.MyEvent += h, h => obj.MyEvent -= h);","handlingStrategy":"validation","validationCode":"if (removeHandler is null) throw new ArgumentNullException(nameof(removeHandler));","typeGuard":"static bool HasRemove<TEventArgs>(Action<Action<TEventArgs>>? remove) => remove is not null;","tryCatchPattern":"try { var obs = AsyncObservable.FromEvent<EventArgs>(add, remove); } catch (ArgumentNullException ex) when (ex.ParamName == \"removeHandler\") { log.LogError(ex, \"removeHandler required to detach on dispose\"); }","preventionTips":["Always implement the unsubscribe side.","Avoid events with add-only accessors when wrapping with FromEvent.","Review refactored wrapper code for dropped -= lambdas."],"tags":["argumentnull","fromevent","csharp","event-handlers"],"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"}