{"record":{"id":"58bd84213650c172","repo":"dotnet/reactive","slug":"strings-linq-event-winrt-remove-method-should-take-ert","errorCode":null,"errorMessage":"Strings_Linq.EVENT_WINRT_REMOVE_METHOD_SHOULD_TAKE_ERT","messagePattern":"Strings_Linq\\.EVENT_WINRT_REMOVE_METHOD_SHOULD_TAKE_ERT","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"Rx.NET/Source/src/System.Reactive/Internal/ReflectionUtils.cs","lineNumber":65,"sourceCode":"                throw new InvalidOperationException(Strings_Linq.EVENT_ADD_METHOD_SHOULD_TAKE_ONE_PARAMETER);\n            }\n\n            var psr = removeMethod.GetParameters();\n            if (psr.Length != 1)\n            {\n                throw new InvalidOperationException(Strings_Linq.EVENT_REMOVE_METHOD_SHOULD_TAKE_ONE_PARAMETER);\n            }\n\n            isWinRT = false;\n\n            if (IsWinRTEventRegistrationTokenType(addMethod.ReturnType))\n            {\n                isWinRT = true;\n\n                var pet = psr[0];\n                if (IsWinRTEventRegistrationTokenType(pet.ParameterType))\n                {\n                    throw new InvalidOperationException(Strings_Linq.EVENT_WINRT_REMOVE_METHOD_SHOULD_TAKE_ERT);\n                }\n            }\n\n            delegateType = psa[0].ParameterType;\n\n            var invokeMethod = delegateType.GetMethod(\"Invoke\")!; // NB: Delegates always have an Invoke method.\n\n            var parameters = invokeMethod.GetParameters();\n\n            if (parameters.Length != 2)\n            {\n                throw new InvalidOperationException(Strings_Linq.EVENT_PATTERN_REQUIRES_TWO_PARAMETERS);\n            }\n\n            if (!typeof(TSender).IsAssignableFrom(parameters[0].ParameterType))\n            {\n                throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, Strings_Linq.EVENT_SENDER_NOT_ASSIGNABLE, typeof(TSender).FullName));\n            }","sourceCodeStart":47,"sourceCodeEnd":83,"githubUrl":"https://github.com/dotnet/reactive/blob/94b5d5ab912789f5abe9a72138a25bbd716fe59c/Rx.NET/Source/src/System.Reactive/Internal/ReflectionUtils.cs#L47-L83","documentation":"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.","triggerScenarios":"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.","commonSituations":"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).","solutions":["Make the remove accessor accept a single Windows.Foundation.EventRegistrationToken parameter to match the add accessor's return type.","Regenerate the WinRT interop types with cswinrt / the current Windows SDK metadata so add/remove conventions match.","Wrap the event manually with Observable.Create if you cannot fix the interop type."],"exampleFix":"// before\npublic void remove_E(EventHandler h) { ... }\n// after\npublic void remove_E(EventRegistrationToken t) { ... }","handlingStrategy":"validation","validationCode":"var remove = type.GetMethod(\"remove_\" + name);\nvar p = remove?.GetParameters();\nif (p == null || p.Length != 1 || p[0].ParameterType.Name != \"EventRegistrationToken\")\n    throw new ArgumentException(\"WinRT event remove accessor must take EventRegistrationToken\");","typeGuard":null,"tryCatchPattern":"try { Observable.FromEventPattern(target, eventName); }\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"ERT\") || ex.Message.Contains(\"EventRegistrationToken\"))\n{\n    // use platform-specific WinRT event extension or manual wiring\n}","preventionTips":["Regenerate WinRT interop assemblies with current cswinrt tooling.","Never hand-edit projected WinRT event accessors.","Target .NET versions with proper WinRT projection support."],"tags":["winrt","reflection","events"],"backgroundTag":"type-mismatch","analyzedSha":"94b5d5ab912789f5abe9a72138a25bbd716fe59c","analyzedAt":"2026-09-15T02:26:24.759Z","contentChangedAt":"2026-09-15T02:26:24.759Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}