dotnet/reactive · error · InvalidOperationException

The sender parameter of the event is not assignable to

Error message

The sender parameter of the event is not assignable to '{0}'.

What it means

After checking parameter count, GetEventMethods verifies that the delegate's first parameter type is assignable to TSender (typically object). This InvalidOperationException fires when the sender slot of the delegate has a type that TSender cannot accept, so the FromEventPattern adapter cannot safely deliver the sender argument as TSender.

Solutions

  1. Make TSender assignable-from the delegate's first parameter, typically use object for TSender
  2. Match the delegate's sender parameter type exactly, e.g. FromEventPattern<MyControl, MyEventArgs> for a delegate taking (MyControl sender, MyEventArgs e)
  3. Inspect the delegate: typeof(D).GetMethod("Invoke").GetParameters()[0].ParameterType and ensure TSender.IsAssignableFrom(that type)

Example fix

// before
AsyncObservable.FromEventPattern<object, MyEventArgs>(...) // delegate sender is MyControl, object is not assignable FROM MyControl? -> use actual types
// after
AsyncObservable.FromEventPattern<MyControl, MyEventArgs>(...)
Defensive patterns

Strategy: validation

Validate before calling

var p = typeof(MyDelegate).GetMethod("Invoke").GetParameters();
if (!typeof(TSender).IsAssignableFrom(p[0].ParameterType))
    throw new InvalidOperationException($"TSender must accept {p[0].ParameterType}");

Type guard

static bool SenderCompatible<TSender>(Type d)
    => typeof(TSender).IsAssignableFrom(d.GetMethod("Invoke")?.GetParameters()[0].ParameterType);

Try / catch

try
{
    var obs = AsyncObservable.FromEventPattern<TSender, TEventArgs>(add, remove);
}
catch (InvalidOperationException ex) when (ex.Message.Contains("sender parameter"))
{
    // retry with TSender = the delegate's actual sender parameter type
}

Prevention

When it happens

Trigger: Calling FromEventPattern<TSender, TEventArgs> with a delegate whose first Invoke parameter is a concrete type (e.g. MyControl) while TSender is a base type like object, or TSender set to a type unrelated to the delegate's actual sender parameter.

Common situations: Specifying an incorrect TSender generic argument (e.g. typeof(object) expected but the delegate narrows the sender); using custom delegates with strongly-typed senders; copy-pasting generic arguments from another event.

Understand the failure class

Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.

Related errors


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

Appendix: source

Thrown at AsyncRx.NET/System.Reactive.Async/Linq/Operators/FromEventPattern.cs:316

            {
                isWinRT = true;

                var pet = psr[0];
                if (pet.ParameterType != addMethod.ReturnType)
                    throw new InvalidOperationException("An event should either have add and remove methods that return void or an add method that returns a type compatible with the parameter type of the remove method.");
            }

            var delegateType = psa[0].ParameterType;

            var invokeMethod = delegateType.GetMethod("Invoke");

            var parameters = invokeMethod.GetParameters();

            if (parameters.Length != 2)
                throw new InvalidOperationException("The delegate type for an event conforming to the traditional event pattern should take two parameters.");

            if (!typeof(TSender).IsAssignableFrom(parameters[0].ParameterType))
                throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, "The sender parameter of the event is not assignable to '{0}'.", typeof(TSender).FullName));

            if (!typeof(TEventArgs).IsAssignableFrom(parameters[1].ParameterType))
                throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, "The event arguments parameter of the event is not assignable to '{0}'.", typeof(TEventArgs).FullName));

            if (invokeMethod.ReturnType != typeof(void))
                throw new InvalidOperationException("The return type of an event delegate should be void.");

            return (addMethod, removeMethod, delegateType, isWinRT);
        }

        public static EventInfo GetEventEx(this Type type, string name, bool isStatic)
        {
            return type.GetEvent(name, isStatic ? BindingFlags.Public | BindingFlags.Static : BindingFlags.Public | BindingFlags.Instance);
        }
    }
}

View on GitHub (pinned to 94b5d5ab91)