dotnet/reactive · error · InvalidOperationException
Strings_Linq.EVENT_REMOVE_METHOD_SHOULD_TAKE_ONE_PARAMETER
Error message
Strings_Linq.EVENT_REMOVE_METHOD_SHOULD_TAKE_ONE_PARAMETER
What it means
GetEventMethods validates that an event's remove accessor (remove_X) takes exactly one parameter, matching the add accessor. Rx's FromEventPattern uses reflection to wire observable subscriptions to CLR events, and a remove method with a parameter count other than 1 cannot be invoked with a single subscription token. The library throws InvalidOperationException to fail fast on events that do not follow the standard event pattern.
Solutions
- Fix the event's remove accessor so it takes exactly one parameter of the same delegate type as the add accessor.
- Verify you passed the correct event name / addMethod-removeMethod pair to FromEventPattern; a wrong pair can pick up an invalid accessor.
- If the event is truly non-standard, do not use FromEventPattern; wrap the event manually with Observable.Create and a custom unsubscribe.
Example fix
// before
public event EventHandler E { add { } remove { } } // remove has 0 params
// after
private EventHandler _e;
public event EventHandler E { add { _e += value; } remove { _e -= value; } } Defensive patterns
Strategy: validation
Validate before calling
var add = type.GetMethod("add_" + name);
var remove = type.GetMethod("remove_" + name);
if (remove == null || remove.GetParameters().Length != 1)
throw new ArgumentException($"Event {name}: remove accessor must take exactly one parameter"); Try / catch
try
{
var source = Observable.FromEventPattern(target, eventName);
}
catch (InvalidOperationException ex) when (ex.Message.Contains("remove method"))
{
// fall back to manual Observable.Create wiring
} Prevention
- Keep add/remove accessors symmetric: one parameter, same delegate type.
- Prefer compiler-generated events (field-like events) over hand-written accessors.
- Unit-test reflection-based event wiring on the target types.
When it happens
Trigger: Calling Observable.FromEventPattern/FromEvent with an event whose remove method (e.g. remove_EventName) has zero or multiple parameters, discovered via ReflectionUtils.GetEventMethods.
Common situations: Reflecting over custom or third-party classes with hand-written add/remove accessors; COM or WinRT interop types with non-standard remove signatures; code-generation output that desynchronized add and remove accessors.
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
- The delegate type for an event conforming to the traditional
- The return type of an event delegate should be void.
- Strings_Linq.EVENT_WINRT_REMOVE_METHOD_SHOULD_TAKE_ERT
- Strings_Linq.EVENT_PATTERN_REQUIRES_TWO_PARAMETERS
- Strings_Linq.EVENT_MUST_RETURN_VOID
AI-assisted analysis of dotnet/reactive@94b5d5ab91 (2026-09-15).
Data as JSON: /api/errors/365c43e238f0de96.
Report an issue: GitHub.
Appendix: source
Thrown at Rx.NET/Source/src/System.Reactive/Internal/ReflectionUtils.cs:53
else
{
e = targetType.GetEvent(eventName, BindingFlags.Public | BindingFlags.Instance)
?? throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, Strings_Linq.COULD_NOT_FIND_INSTANCE_EVENT, eventName, targetType.FullName));
}
addMethod = e.GetAddMethod() ?? throw new InvalidOperationException(Strings_Linq.EVENT_MISSING_ADD_METHOD);
removeMethod = e.GetRemoveMethod() ?? throw new InvalidOperationException(Strings_Linq.EVENT_MISSING_REMOVE_METHOD);
var psa = addMethod.GetParameters();
if (psa.Length != 1)
{
throw new InvalidOperationException(Strings_Linq.EVENT_ADD_METHOD_SHOULD_TAKE_ONE_PARAMETER);
}
var psr = removeMethod.GetParameters();
if (psr.Length != 1)
{
throw new InvalidOperationException(Strings_Linq.EVENT_REMOVE_METHOD_SHOULD_TAKE_ONE_PARAMETER);
}
isWinRT = false;
if (IsWinRTEventRegistrationTokenType(addMethod.ReturnType))
{
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.View on GitHub (pinned to 94b5d5ab91)