dotnet/reactive · error · ArgumentNullException
removeHandler
Error message
removeHandler
What it means
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.
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.
Example fix
// before var obs = AsyncObservable.FromEvent<EventArgs>(h => obj.MyEvent += h, null); // after var obs = AsyncObservable.FromEvent<EventArgs>(h => obj.MyEvent += h, h => obj.MyEvent -= h);
Defensive patterns
Strategy: validation
Validate before calling
if (removeHandler is null) throw new ArgumentNullException(nameof(removeHandler));
Type guard
static bool HasRemove<TEventArgs>(Action<Action<TEventArgs>>? remove) => remove is not null;
Try / catch
try { var obs = AsyncObservable.FromEvent<EventArgs>(add, remove); } catch (ArgumentNullException ex) when (ex.ParamName == "removeHandler") { log.LogError(ex, "removeHandler required to detach on dispose"); } Prevention
- Always implement the unsubscribe side.
- Avoid events with add-only accessors when wrapping with FromEvent.
- Review refactored wrapper code for dropped -= lambdas.
When it happens
Trigger: Calling AsyncObservable.FromEvent<TEventArgs>(addHandler, removeHandler) with removeHandler == null; FromEvent.cs:19 is the `throw new ArgumentNullException(nameof(removeHandler))`.
Common situations: 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.
Related errors
- addHandler
- Value cannot be null. (Parameter 'observer')
- ArgumentNull_Generic
- conversion
- Value cannot be null. (Parameter 'action')
AI-assisted analysis of dotnet/reactive@94b5d5ab91 (2026-09-15).
Data as JSON: /api/errors/af4834a86f9156df.
Report an issue: GitHub.
Appendix: source
Thrown at AsyncRx.NET/System.Reactive.Async/Linq/Operators/FromEvent.cs:19
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT License.
// See the LICENSE file in the project root for more information.
using System.Reactive.Concurrency;
using System.Reactive.Disposables;
using System.Threading;
using System.Threading.Tasks;
namespace System.Reactive.Linq
{
public partial class AsyncObservable
{
public static IAsyncObservable<TEventArgs> FromEvent<TEventArgs>(Action<Action<TEventArgs>> addHandler, Action<Action<TEventArgs>> removeHandler)
{
if (addHandler == null)
throw new ArgumentNullException(nameof(addHandler));
if (removeHandler == null)
throw new ArgumentNullException(nameof(removeHandler));
return FromEventCore<Action<TEventArgs>, TEventArgs>(h => h, addHandler, removeHandler, GetSchedulerForCurrentContext());
}
public static IAsyncObservable<TEventArgs> FromEvent<TEventArgs>(Action<Action<TEventArgs>> addHandler, Action<Action<TEventArgs>> removeHandler, IAsyncScheduler scheduler)
{
if (addHandler == null)
throw new ArgumentNullException(nameof(addHandler));
if (removeHandler == null)
throw new ArgumentNullException(nameof(removeHandler));
if (scheduler == null)
throw new ArgumentNullException(nameof(scheduler));
return FromEventCore<Action<TEventArgs>, TEventArgs>(h => h, addHandler, removeHandler, scheduler);
}
public static IAsyncObservable<TEventArgs> FromEvent<TDelegate, TEventArgs>(Action<TDelegate> addHandler, Action<TDelegate> removeHandler)
{View on GitHub (pinned to 94b5d5ab91)