dotnet/reactive · error · ArgumentNullException

conversion

Error message

conversion

What it means

The generic FromEvent<TDelegate, TEventArgs> requires a conversion function that turns Action<TEventArgs> into the target delegate type. When conversion is null the guard throws ArgumentNullException with ParamName "conversion" because the operator cannot bridge the framework event delegate to the handler pipeline.

Solutions

  1. Supply the conversion lambda, e.g. h => (EventHandler)h for EventHandler-based events.
  2. Use the non-generic FromEvent(Action<Action>, ...) overload if the event already accepts Action.
  3. Use FromEventPattern for EventHandler events, which supplies the conversion internally.

Example fix

// before
var sub = AsyncRx.Observable.FromEvent<EventHandler, EventArgs>(null, h => src.Clicked += h, h => src.Clicked -= h);
// after
var sub = AsyncRx.Observable.FromEvent<EventHandler, EventArgs>(h => (EventHandler)((_, e) => h(e)), h => src.Clicked += h, h => src.Clicked -= h);
Defensive patterns

Strategy: validation

Validate before calling

if (conversion == null) conversion = h => (EventHandler)((_, e) => h(e));

Type guard

bool HasConversion<TDelegate, TEventArgs>(Func<Action<TEventArgs>, TDelegate> conversion) => conversion != null;

Try / catch

try { var sub = FromEvent<TDelegate, TEventArgs>(conversion, add, remove); }
catch (ArgumentNullException ex) when (ex.ParamName == "conversion") { /* build a default conversion for the delegate type */ }

Prevention

When it happens

Trigger: Calling FromEvent<TDelegate, TEventArgs>(null, addHandler, removeHandler), e.g. omitting the conversion lambda when subscribing to a non-Action event like EventHandler or a custom delegate.

Common situations: Subscribing to events whose delegate type is not Action<TEventArgs> (EventHandler, PropertyChangedEventHandler) and leaving the conversion slot empty; constructing the arguments dynamically where the converter string/delegate is null.

Related errors


AI-assisted analysis of dotnet/reactive@94b5d5ab91 (2026-09-15). Data as JSON: /api/errors/e22c4c87e0965d4a. Report an issue: GitHub.

Appendix: source

Thrown at AsyncRx.NET/System.Reactive.Async/Linq/Operators/FromEvent.cs:83

            return FromEventCore<Action, Unit>(h => () => h(Unit.Default), addHandler, removeHandler, GetSchedulerForCurrentContext());
        }

        public static IAsyncObservable<Unit> FromEvent(Action<Action> addHandler, Action<Action> 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, Unit>(h => () => h(Unit.Default), addHandler, removeHandler, scheduler);
        }

        public static IAsyncObservable<TEventArgs> FromEvent<TDelegate, TEventArgs>(Func<Action<TEventArgs>, TDelegate> conversion, Action<TDelegate> addHandler, Action<TDelegate> removeHandler)
        {
            if (conversion == null)
                throw new ArgumentNullException(nameof(conversion));
            if (addHandler == null)
                throw new ArgumentNullException(nameof(addHandler));
            if (removeHandler == null)
                throw new ArgumentNullException(nameof(removeHandler));

            return FromEventCore(conversion, addHandler, removeHandler, GetSchedulerForCurrentContext());
        }

        public static IAsyncObservable<TEventArgs> FromEvent<TDelegate, TEventArgs>(Func<Action<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));

View on GitHub (pinned to 94b5d5ab91)