dotnet/reactive · error · ArgumentNullException
ArgumentNull_Generic
Error message
ArgumentNull_Generic
What it means
FromEvent converts .NET-style add/removeHandler event subscriptions into an async observable. This overload accepts a conversion delegate (Action<T1,T2> -> TDelegate), add/remove handlers, and a scheduler; it throws ArgumentNullException (rendered here as the generic ArgumentNull_Generic message) when any of `conversion`, `addHandler`, `removeHandler`, or `scheduler` is null.
Solutions
- Supply all four arguments: a conversion such as `h => ( EventHandler)h.Invoke` (matching TDelegate), non-null addHandler/removeHandler, and a scheduler like AsyncScheduler.Immediate (or the library's default).
- Use the simpler overload FromEvent(addHandler, removeHandler) that internally supplies `h => h` conversion and GetSchedulerForCurrentContext() when you don't need custom conversion/scheduling.
- Check the source of the scheduler argument; if it comes from configuration or a factory, assert non-null before calling.
Example fix
// before AsyncObservable.FromEvent<Action<int,string>, int, string>(null, addHandler, removeHandler, null); // after var conv = new Func<Action<int,string>, Action<int,string>>(h => h); // or real delegate conversion AsyncObservable.FromEvent<Action<int,string>, int, string>(conv, addHandler, removeHandler, AsyncScheduler.Immediate);
Defensive patterns
Strategy: validation
Validate before calling
if (conversion is null || addHandler is null || removeHandler is null || scheduler is null)
throw new ArgumentNullException(conversion is null ? nameof(conversion)
: addHandler is null ? nameof(addHandler)
: removeHandler is null ? nameof(removeHandler) : nameof(scheduler)); Type guard
bool CanWire<TDel>(Func<Action<TDel>,TDel> conversion, Action<TDel> add, Action<TDel> remove, IAsyncScheduler sched)
=> conversion is not null && add is not null && remove is not null && sched is not null; Try / catch
try
{
var obs = AsyncObservable.FromEvent<TDelegate,int,string>(conversion, addHandler, removeHandler, scheduler);
}
catch (ArgumentNullException ex)
{
// ex.ParamName tells which of conversion/addHandler/removeHandler/scheduler was null
} Prevention
- Use the two-argument FromEvent overload unless you specifically need custom conversion or scheduler.
- Resolve the scheduler from a guaranteed default (AsyncScheduler.Immediate / Default) rather than nullable DI lookups.
- Keep event add/remove accessors as +=/-= lambdas on a fully constructed target.
When it happens
Trigger: Calling the FromEvent<T1,T2> overload that takes (conversion, addHandler, removeHandler, scheduler) with any of those four arguments null - e.g. a scheduler obtained from a resolver that returned null, or an event handler registry with no add/remove hooks registered.
Common situations: Passing a scheduler from DI or a context provider that returned null; wiring events dynamically where the add/remove accessor delegates are null; forgetting the conversion lambda in the overload that requires it.
Related errors
- Value cannot be null. (Parameter 'action')
- scheduler
- scheduler
- Argument cannot be null (Parameter name: scheduler)
- Value cannot be null. (Parameter 'observer')
AI-assisted analysis of dotnet/reactive@94b5d5ab91 (2026-09-15).
Data as JSON: /api/errors/e7f0a945bffd9644.
Report an issue: GitHub.
Appendix: source
Thrown at AsyncRx.NET/System.Reactive.Async/Linq/Operators/FromEvent.Generated.cs:56
throw new ArgumentNullException(nameof(conversion));
if (addHandler == null)
throw new ArgumentNullException(nameof(addHandler));
if (removeHandler == null)
throw new ArgumentNullException(nameof(removeHandler));
return FromEventCore<TDelegate, T1, T2>(conversion, addHandler, removeHandler, GetSchedulerForCurrentContext());
}
public static IAsyncObservable<(T1 arg1, T2 arg2)> FromEvent<TDelegate, T1, T2>(Func<Action<T1, T2>, TDelegate> conversion, Action<TDelegate> addHandler, Action<TDelegate> removeHandler, IAsyncScheduler scheduler)
{
if (conversion == null)
throw new ArgumentNullException(nameof(conversion));
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<TDelegate, T1, T2>(conversion, addHandler, removeHandler, scheduler);
}
private static IAsyncObservable<(T1 arg1, T2 arg2)> FromEventCore<TDelegate, T1, T2>(Func<Action<T1, T2>, TDelegate> conversion, Action<TDelegate> addHandler, Action<TDelegate> removeHandler, IAsyncScheduler scheduler)
{
return
SynchronizeEvents(
Create<(T1 arg1, T2 arg2)>(observer =>
{
var handler = new Action<T1, T2>((arg1, arg2) =>
{
observer.OnNextAsync((arg1, arg2)); // REVIEW: Fire-and-forget can lead to out of order processing, and observers may reject these calls as "busy".
});
var converted = conversion(handler);
addHandler(converted);View on GitHub (pinned to 94b5d5ab91)