dotnet/reactive · error · InvalidOperationException

Strings_Linq.EVENT_ARGS_NOT_ASSIGNABLE

Error message

Strings_Linq.EVENT_ARGS_NOT_ASSIGNABLE

What it means

FromEventPattern<TSender, TEventArgs> requires the event delegate's second parameter (the event-args parameter) to be assignable from TEventArgs. GetEventMethods throws InvalidOperationException when TEventArgs is not compatible with the delegate's args parameter type.

Solutions

  1. Set TEventArgs to the exact (or assignable-from) type used by the delegate, e.g. KeyEventArgs for KeyboardEventHandler.
  2. Inspect the delegate's Invoke signature to confirm the second parameter type before writing the call.
  3. Use the string-based FromEventPattern overloads that infer the args type.

Example fix

// before
Observable.FromEventPattern<object, EventArgs>(textBox, nameof(textBox.KeyDown));
// after
Observable.FromEventPattern<object, KeyEventArgs>(textBox, nameof(textBox.KeyDown));
Defensive patterns

Strategy: validation

Validate before calling

var invoke = delegateType.GetMethod("Invoke");
var argsType = invoke?.GetParameters().ElementAtOrDefault(1)?.ParameterType;
if (argsType == null || !argsType.IsAssignableFrom(typeof(TEventArgs)))
    throw new ArgumentException($"TEventArgs must match the delegate's args parameter ({argsType?.Name})");

Try / catch

try
{
    var src = Observable.FromEventPattern<TSender, TEventArgs>(target, eventName);
}
catch (InvalidOperationException ex) when (ex.Message.Contains("args"))
{
    // retry with the delegate's actual args type
}

Prevention

When it happens

Trigger: Calling FromEventPattern<S, MouseEventHandlerArgs>(...) where the delegate's second parameter is, e.g., KeyEventArgs or EventArgs, not the supplied TEventArgs.

Common situations: Guessing the TEventArgs type instead of reading the delegate signature; reusing generic arguments across events; events using custom EventArgs-derived types.

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/11013a1ad9ad5a8d. Report an issue: GitHub.

Appendix: source

Thrown at Rx.NET/Source/src/System.Reactive/Internal/ReflectionUtils.cs:87

            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>
        /// <returns>True if this represents a WinRT event registration token</returns>
        /// <remarks>
        /// <para>
        /// We used to perform a simple comparison with typeof(EventRegistrationToken), but the
        /// introduction of C#/WinRT has made this problematic. Before C#/WinRT, the .NET

View on GitHub (pinned to 94b5d5ab91)