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

  1. Provide a real conversion, e.g. h => (SomeDelegate)((o, ev) => h(o, ev)) or a custom cast for non-standard delegates.
  2. If standard EventHandler<TEventArgs> compatibility suffices, drop the conversion argument and use the non-conversion overload.
  3. Fix the factory producing the conversion so it never returns null (throw with a clear message instead).
  4. 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

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


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)