dotnet/reactive · error · ArgumentNullException
addHandler
Error message
addHandler
What it means
The non-generic, non-converting FromEvent<TEventArgs>(addHandler, removeHandler) in FromEvent.cs null-checks addHandler first. It throws ArgumentNullException with parameter name 'addHandler' when the subscription action is null. addHandler attaches an Action<TEventArgs> to the underlying event; without it the operator cannot subscribe, so it fails fast before returning the observable.
Solutions
- Pass h => source.Event += h as addHandler.
- Ensure the argument is produced before the FromEvent call, not lazily.
- Use the conversion-based overloads when the handler type needs adapting.
- Add a unit test asserting non-null arguments when building event wrappers.
Example fix
// before var obs = AsyncObservable.FromEvent<EventArgs>(null, h => obj.MyEvent -= h); // after var obs = AsyncObservable.FromEvent<EventArgs>(h => obj.MyEvent += h, h => obj.MyEvent -= h);
Defensive patterns
Strategy: validation
Validate before calling
if (addHandler is null) throw new ArgumentNullException(nameof(addHandler)); if (removeHandler is null) throw new ArgumentNullException(nameof(removeHandler));
Type guard
static bool Valid<TEventArgs>(Action<Action<TEventArgs>>? add, Action<Action<TEventArgs>>? remove) => add != null && remove != null;
Try / catch
try { var obs = AsyncObservable.FromEvent<EventArgs>(add, remove); } catch (ArgumentNullException ex) { log.LogError(ex, "FromEvent requires non-null {Param}", ex.ParamName); } Prevention
- Pass += and -= lambdas inline for classic events.
- Null-check delegate fields before using them as handlers.
- Write a small helper that enforces non-null add/remove for your event sources.
When it happens
Trigger: Calling AsyncObservable.FromEvent<TEventArgs>(addHandler, removeHandler) with addHandler == null; FromEvent.cs:17 is that `throw new ArgumentNullException(nameof(addHandler))`.
Common situations: Wrapping classic events like button.Click where the add lambda was omitted; passing a nullable delegate field not yet assigned; generic helper that takes add/remove and receives null from its caller.
Related errors
- removeHandler
- 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/cd86d8ef300adb57.
Report an issue: GitHub.
Appendix: source
Thrown at AsyncRx.NET/System.Reactive.Async/Linq/Operators/FromEvent.cs:17
// 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);
}
View on GitHub (pinned to 94b5d5ab91)