dotnet/reactive · error · InvalidOperationException

Strings_Linq.EVENT_PATTERN_REQUIRES_TWO_PARAMETERS

Error message

Strings_Linq.EVENT_PATTERN_REQUIRES_TWO_PARAMETERS

What it means

The delegate behind the event must follow the .NET event pattern: two parameters (sender, eventArgs). Rx's FromEventPattern projects events into (TSender, TEventArgs) pairs, so a delegate's Invoke method with a parameter count other than 2 cannot be adapted. GetEventMethods throws InvalidOperationException when this invariant fails.

Solutions

  1. Use a delegate type conforming to the event pattern, e.g. EventHandler<TEventArgs> or a custom delegate with (object sender, TEventArgs e).
  2. If the event really passes only a payload, use Observable.FromEvent instead of FromEventPattern.
  3. Check that the event name string passed to FromEventPattern resolves to the intended event.

Example fix

// before
public event Action<int> Tick;
// after
public event EventHandler<int> Tick;
Defensive patterns

Strategy: validation

Validate before calling

var invoke = delegateType.GetMethod("Invoke");
if (invoke == null || invoke.GetParameters().Length != 2)
    throw new ArgumentException("Delegate must follow (object sender, TEventArgs e) pattern");

Try / catch

try
{
    var src = Observable.FromEventPattern<TSender, TEventArgs>(target, eventName);
}
catch (InvalidOperationException ex) when (ex.Message.Contains("two parameters"))
{
    var src2 = Observable.FromEvent<Action<TPayload>, TPayload>(h => h.Invoke, h => target.Event += h, h => target.Event -= h);
}

Prevention

When it happens

Trigger: Calling FromEventPattern<TSender, TEventArgs> with an event whose delegate type (or the delegate of the add method's parameter) has an Invoke method taking 0, 1, or 3+ parameters.

Common situations: Using delegates like Action or custom single-arg delegates (e.g. Action<string> callbacks) as 'events'; passing the wrong event name so reflection resolves an unrelated delegate; migrating code to FromEvent (delegate-based) when FromEventPattern (sender/args) was assumed.

Understand the failure class

Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.

Related errors


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

Appendix: source

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

            {
                isWinRT = true;

                var pet = psr[0];
                if (IsWinRTEventRegistrationTokenType(pet.ParameterType))
                {
                    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);
            }
        }

View on GitHub (pinned to 94b5d5ab91)