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

  1. Set TSender to a type the delegate's first parameter is assignable from — for typical CLR events use FromEventPattern<object, TEventArgs>.
  2. Match the delegate exactly: if the event uses EventHandler, TSender must be object.
  3. 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

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


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)