dotnet/reactive · error · InvalidOperationException

Strings_Linq.EVENT_WINRT_REMOVE_METHOD_SHOULD_TAKE_ERT

Error message

Strings_Linq.EVENT_WINRT_REMOVE_METHOD_SHOULD_TAKE_ERT

What it means

For WinRT events, the remove accessor must take an EventRegistrationToken, not the delegate type. GetEventMethods detects a WinRT event (add method returns an EventRegistrationToken) and then validates the remove parameter; if the remove parameter is not an EventRegistrationToken the pattern is inconsistent and Rx throws InvalidOperationException.

Solutions

  1. Make the remove accessor accept a single Windows.Foundation.EventRegistrationToken parameter to match the add accessor's return type.
  2. Regenerate the WinRT interop types with cswinrt / the current Windows SDK metadata so add/remove conventions match.
  3. Wrap the event manually with Observable.Create if you cannot fix the interop type.

Example fix

// before
public void remove_E(EventHandler h) { ... }
// after
public void remove_E(EventRegistrationToken t) { ... }
Defensive patterns

Strategy: validation

Validate before calling

var remove = type.GetMethod("remove_" + name);
var p = remove?.GetParameters();
if (p == null || p.Length != 1 || p[0].ParameterType.Name != "EventRegistrationToken")
    throw new ArgumentException("WinRT event remove accessor must take EventRegistrationToken");

Try / catch

try { Observable.FromEventPattern(target, eventName); }
catch (InvalidOperationException ex) when (ex.Message.Contains("ERT") || ex.Message.Contains("EventRegistrationToken"))
{
    // use platform-specific WinRT event extension or manual wiring
}

Prevention

When it happens

Trigger: Calling FromEventPattern on a WinRT event whose remove_X accessor takes a delegate instead of a Windows.Foundation.EventRegistrationToken while the add_X accessor returns a token.

Common situations: Mixed/mismatched WinRT projections; manually authored interop stubs where add and remove use different conventions; consuming WinRT metadata converted with incorrect tooling on .NET (pre-.NET Core 3 WinRT support changes).

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/58bd84213650c172. Report an issue: GitHub.

Appendix: source

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

                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.

            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));
            }

View on GitHub (pinned to 94b5d5ab91)