dotnet/reactive · error · InvalidOperationException

The remove method of an event should take one parameter.

Error message

The remove method of an event should take one parameter.

What it means

Symmetric to the add accessor check: the remove accessor must take exactly one delegate parameter. GetEventMethods throws InvalidOperationException when removeMethod.GetParameters() has a length other than 1.

Solutions

  1. Fix the event declaration to the standard pattern: remove takes a single delegate parameter
  2. If an extra token is genuinely needed, use the FromEvent overload with explicit add/remove delegates instead of name-based lookup
  3. Inspect removeMethod.GetParameters() to confirm the offending signature

Example fix

// before
public event EventHandler Tick {
  add { _tick += value; }
  remove { _tick -= value; _token = null; } // ok; but IL with (delegate, token) breaks
}
// after
public event EventHandler Tick; // standard accessors, one parameter each
Defensive patterns

Strategy: validation

Validate before calling

var ev = type.GetEvent(eventName);
var remove = ev?.GetRemoveMethod();
if (remove is null || remove.GetParameters().Length != 1) throw new NotSupportedException($"Event '{eventName}' remove accessor must take exactly one delegate parameter.");

Type guard

static bool HasValidRemoveSignature(Type t, string name) => t.GetEvent(name)?.GetRemoveMethod()?.GetParameters().Length == 1;

Prevention

When it happens

Trigger: Events whose remove accessor signature deviates from the CLR event pattern (custom IL, weaved code, or platform projections with extra parameters).

Common situations: Custom event store implementations with a removal token parameter, post-processing tools altering signatures, mis-declared events in COM/WinRT interop layers.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


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

Appendix: source

Thrown at AsyncRx.NET/System.Reactive.Async/Linq/Operators/FromEventPattern.cs:293

                if (e == null)
                    throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, "Could not find instance event '{0}' on type '{1}'.", eventName, targetType.FullName));
            }

            var addMethod = e.GetAddMethod();
            var removeMethod = e.GetRemoveMethod();

            if (addMethod == null)
                throw new InvalidOperationException("Missing add method on event.");
            if (removeMethod == null)
                throw new InvalidOperationException("Missing remove method on event.");

            var psa = addMethod.GetParameters();
            if (psa.Length != 1)
                throw new InvalidOperationException("The add method of an event should take one parameter.");

            var psr = removeMethod.GetParameters();
            if (psr.Length != 1)
                throw new InvalidOperationException("The remove method of an event should take one parameter.");

            var isWinRT = false;

            if (addMethod.ReturnType != typeof(void))
            {
                isWinRT = true;

                var pet = psr[0];
                if (pet.ParameterType != addMethod.ReturnType)
                    throw new InvalidOperationException("An event should either have add and remove methods that return void or an add method that returns a type compatible with the parameter type of the remove method.");
            }

            var delegateType = psa[0].ParameterType;

            var invokeMethod = delegateType.GetMethod("Invoke");

            var parameters = invokeMethod.GetParameters();

View on GitHub (pinned to 94b5d5ab91)