dotnet/reactive · error · InvalidOperationException

Strings_Linq.EVENT_MISSING_REMOVE_METHOD

Error message

Strings_Linq.EVENT_MISSING_REMOVE_METHOD

What it means

Symmetric to 2577: GetEventMethods also requires a remove accessor to support unsubscription. If e.GetRemoveMethod() returns null (remove accessor non-public or absent), it throws InvalidOperationException 'Event missing remove method'.

Solutions

  1. Make the event's remove accessor public.
  2. Use the FromEventPattern overload taking explicit addHandler/removeHandler delegates so remove is under your control.
  3. Manually manage lifetime: subscribe via add accessor and never rely on library-driven removal — though prefer fixing visibility.

Example fix

// before
public event EventHandler E { add { _e += value; } private remove { _e -= value; } }
// after
public event EventHandler E { add { _e += value; } remove { _e -= value; } }
Defensive patterns

Strategy: validation

Validate before calling

var evt = targetType.GetEvent(eventName, BindingFlags.Public | BindingFlags.Instance);
if (evt?.GetRemoveMethod() == null) throw new NotSupportedException($"Event '{eventName}' has no public remove accessor");

Type guard

static bool HasPublicRemove(Type t, string name) => t.GetEvent(name)?.GetRemoveMethod() != null;

Try / catch

try { Observable.FromEventPattern(target, eventName, targetType); } catch (InvalidOperationException ex) when (ex.Message.Contains("remove method")) { /* use explicit add/remove overloads */ }

Prevention

When it happens

Trigger: FromEventPattern against an event with a public add but non-public/missing remove accessor (asymmetric custom accessors).

Common situations: Custom event implementations where remove was made private; events whose remove accessor is only in an explicitly implemented non-public interface; reflection-only loading scenarios.

Understand the failure class

Background: "not installed", "pip install", "required for": how missing-dependency errors surface across open-source libraries — this error's family across 34 libraries.

Related errors


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

Appendix: source

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

    [RequiresUnreferencedCode(Constants_Core.EventReflectionTrimIncompatibilityMessage)]
#endif
        public static void GetEventMethods<TSender, TEventArgs>(Type targetType, object? target, string eventName, out MethodInfo addMethod, out MethodInfo removeMethod, out Type delegateType, out bool isWinRT)
        {
            EventInfo? e;

            if (target == null)
            {
                e = targetType.GetEvent(eventName, BindingFlags.Public | BindingFlags.Static)
                    ?? throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, Strings_Linq.COULD_NOT_FIND_STATIC_EVENT, eventName, targetType.FullName));
            }
            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;

View on GitHub (pinned to 94b5d5ab91)