dotnet/reactive · error · ArgumentNullException
conversion
Error message
conversion
What it means
System.ArgumentNullException with param name 'conversion'. The conversion-based overload FromEventPattern<TDelegate, TEventArgs>(conversion, addHandler, removeHandler, scheduler) expects a Func<EventHandler<TEventArgs>, TDelegate> that adapts the library's handler to your event's delegate type; a null conversion throws immediately because FromEvent cannot build handlers without it.
Solutions
- Provide a real conversion, e.g. h => (SomeDelegate)((o, ev) => h(o, ev)) or a custom cast for non-standard delegates.
- If standard EventHandler<TEventArgs> compatibility suffices, drop the conversion argument and use the non-conversion overload.
- Fix the factory producing the conversion so it never returns null (throw with a clear message instead).
- Check argument order — conversion is the FIRST parameter of this overload.
Example fix
// before
var obs = AsyncObservable.FromEventPattern<MyDelegate, MyArgs>(
null,
h => target.E += h,
h => target.E -= h);
// after
var obs = AsyncObservable.FromEventPattern<MyDelegate, MyArgs>(
h => new MyDelegate((o, a) => h(o, a)),
x => target.E += x,
x => target.E -= x); Defensive patterns
Strategy: validation
Validate before calling
if (conversion == null) throw new ArgumentNullException(nameof(conversion)); // ensure your converter never returns null for supported delegate types
Type guard
static bool ValidConversion<TDelegate>(Func<EventHandler<TEventArgs>, TDelegate> conv) => conv != null;
Try / catch
try
{
var obs = AsyncObservable.FromEventPattern<MyDelegate, MyArgs>(conversion, add, remove);
}
catch (ArgumentNullException ex) when (ex.ParamName == "conversion")
{
// conversion was null; supply a handler adapter
} Prevention
- Remember conversion is the FIRST parameter of this overload.
- Use the non-conversion overload for EventHandler<TEventArgs>-compatible delegates.
- Make converter factories throw with a clear message instead of returning null.
- Cover each custom delegate conversion in unit tests.
When it happens
Trigger: Calling FromEventPattern(null, addHandler, removeHandler[, scheduler]) with any of the conversion-based overloads, e.g. FromEventPattern<SomeDelegate, EventArgs>(null, h => e.AddHandler(h), h => e.RemoveHandler(h)).
Common situations: A converter factory method returns null (unsupported delegate type), or the developer intended the non-conversion overload but called the conversion one and left the first argument null.
Related errors
- removeHandler
- scheduler
- nameof(scheduler)
- nameof(addHandler)
- Value cannot be null. (Parameter 'selector')
AI-assisted analysis of dotnet/reactive@94b5d5ab91 (2026-09-15).
Data as JSON: /api/errors/8f1db81df1bf0864.
Report an issue: GitHub.
Appendix: source
Thrown at AsyncRx.NET/System.Reactive.Async/Linq/Operators/FromEventPattern.cs:53
public static IAsyncObservable<EventPattern<TEventArgs>> FromEventPattern<TDelegate, TEventArgs>(Action<TDelegate> addHandler, Action<TDelegate> 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 FromEvent<TDelegate, object, TEventArgs>(action => ConvertDelegate<Action<object, TEventArgs>, TDelegate>(action), addHandler, removeHandler, scheduler).Select(t => new EventPattern<TEventArgs>(t.arg1, t.arg2));
}
public static IAsyncObservable<EventPattern<TEventArgs>> FromEventPattern<TDelegate, TEventArgs>(Func<EventHandler<TEventArgs>, TDelegate> conversion, Action<TDelegate> addHandler, Action<TDelegate> removeHandler) => FromEventPattern<TDelegate, TEventArgs>(conversion, addHandler, removeHandler, GetSchedulerForCurrentContext());
public static IAsyncObservable<EventPattern<TEventArgs>> FromEventPattern<TDelegate, TEventArgs>(Func<EventHandler<TEventArgs>, 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 FromEvent<TDelegate, object, TEventArgs>(action => conversion(new EventHandler<TEventArgs>((o, e) => action(o, e))), addHandler, removeHandler, scheduler).Select(t => new EventPattern<TEventArgs>(t.arg1, t.arg2));
}
public static IAsyncObservable<EventPattern<TSender, TEventArgs>> FromEventPattern<TDelegate, TSender, TEventArgs>(Action<TDelegate> addHandler, Action<TDelegate> removeHandler) => FromEventPattern<TDelegate, TSender, TEventArgs>(addHandler, removeHandler, GetSchedulerForCurrentContext());
public static IAsyncObservable<EventPattern<TSender, TEventArgs>> FromEventPattern<TDelegate, TSender, TEventArgs>(Action<TDelegate> addHandler, Action<TDelegate> removeHandler, IAsyncScheduler scheduler)
{
if (addHandler == null)
throw new ArgumentNullException(nameof(addHandler));
if (removeHandler == null)
throw new ArgumentNullException(nameof(removeHandler));View on GitHub (pinned to 94b5d5ab91)