dotnet/reactive · error · InvalidOperationException
Strings_Linq.EVENT_SENDER_NOT_ASSIGNABLE
Error message
Strings_Linq.EVENT_SENDER_NOT_ASSIGNABLE
What it means
FromEventPattern<TSender, TEventArgs> requires that the event's delegate first parameter type is assignable from TSender. When the delegate's sender parameter is not compatible with the supplied TSender type argument, GetEventMethods throws InvalidOperationException naming the requested TSender full name.
Solutions
- Set TSender to a type the delegate's first parameter is assignable from — for typical CLR events use FromEventPattern<object, TEventArgs>.
- Match the delegate exactly: if the event uses EventHandler, TSender must be object.
- Alternatively use the non-generic FromEventPattern(eventTarget, eventName) overload and let the library infer types.
Example fix
// before Observable.FromEventPattern<Button, EventArgs>(b, nameof(b.Click)); // after (Click is EventHandler, sender is object) Observable.FromEventPattern<object, EventArgs>(b, nameof(b.Click));
Defensive patterns
Strategy: validation
Validate before calling
var invoke = typeof(EventHandler).GetMethod("Invoke");
var senderType = invoke.GetParameters()[0].ParameterType;
if (!senderType.IsAssignableFrom(typeof(TSender)))
throw new ArgumentException($"TSender must be assignable from {senderType.Name}"); Try / catch
try
{
var src = Observable.FromEventPattern<TSender, TEventArgs>(target, eventName);
}
catch (InvalidOperationException ex) when (ex.Message.Contains("sender"))
{
var src2 = Observable.FromEventPattern<object, TEventArgs>(target, eventName);
} Prevention
- Default to FromEventPattern<object, TEventArgs> for standard CLR events.
- Read the delegate signature to pick TSender instead of copying generic arguments.
- Prefer the overload inferring types from the event itself.
When it happens
Trigger: Calling FromEventPattern<Control, EventArgs>(...) for an event whose delegate's first parameter is object (or a type not related to Control), or any mismatched TSender such as using a derived/mostly-unrelated type.
Common situations: WinForms/WPF events whose sender is object but users specify a concrete control type; typos in generic arguments copied from other events; events using custom sender types while callers assume object.
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
- Strings_Linq.EVENT_ARGS_NOT_ASSIGNABLE
- The event arguments parameter of the event is not…
- The sender parameter of the event is not assignable to
- addHandler
- addHandler
AI-assisted analysis of dotnet/reactive@94b5d5ab91 (2026-09-15).
Data as JSON: /api/errors/a68a520975fb6aab.
Report an issue: GitHub.
Appendix: source
Thrown at Rx.NET/Source/src/System.Reactive/Internal/ReflectionUtils.cs:82
{
throw new InvalidOperationException(Strings_Linq.EVENT_WINRT_REMOVE_METHOD_SHOULD_TAKE_ERT);
}
}
delegateType = psa[0].ParameterType;
var invokeMethod = delegateType.GetMethod("Invoke")!; // NB: Delegates always have an Invoke method.
var parameters = invokeMethod.GetParameters();
if (parameters.Length != 2)
{
throw new InvalidOperationException(Strings_Linq.EVENT_PATTERN_REQUIRES_TWO_PARAMETERS);
}
if (!typeof(TSender).IsAssignableFrom(parameters[0].ParameterType))
{
throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, Strings_Linq.EVENT_SENDER_NOT_ASSIGNABLE, typeof(TSender).FullName));
}
if (!typeof(TEventArgs).IsAssignableFrom(parameters[1].ParameterType))
{
throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, Strings_Linq.EVENT_ARGS_NOT_ASSIGNABLE, typeof(TEventArgs).FullName));
}
if (invokeMethod.ReturnType != typeof(void))
{
throw new InvalidOperationException(Strings_Linq.EVENT_MUST_RETURN_VOID);
}
}
/// <summary>
/// Determine whether a type represents a WinRT event registration token
/// (https://learn.microsoft.com/en-us/uwp/api/windows.foundation.eventregistrationtoken).
/// </summary>
/// <param name="t">The type to check.</param>View on GitHub (pinned to 94b5d5ab91)