{"record":{"id":"99adc4e5f9869e7d","repo":"dotnet/wpf","slug":"sr-freezable-unregisteredhandler","errorCode":null,"errorMessage":"SR.Freezable_UnregisteredHandler","messagePattern":"SR\\.Freezable_UnregisteredHandler","errorType":"exception","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"src/Microsoft.DotNet.Wpf/src/WindowsBase/System/Windows/Freezable.cs","lineNumber":1449,"sourceCode":"            {\n                FrugalObjectList<EventHandler> handlers = HandlerList;\n                int index = handlers.IndexOf(handler);\n\n                if (index >= 0)\n                {\n                    handlers.RemoveAt(index);\n                    failed = false;\n                }\n\n                if (handlers.Count == 0)\n                {\n                    RemoveHandlerList();\n                }\n            }\n\n            if (failed)\n            {\n                throw new ArgumentException(SR.Freezable_UnregisteredHandler, nameof(handler));\n            }\n        }\n\n        //\n        //  Removes the singleton handler the Freezable is storing and resets\n        //  any state indicating this.\n        //\n        private void RemoveSingletonHandler()\n        {\n            Debug.Assert(Freezable_UsingSingletonHandler);\n\n            if (HasContextInformation)\n            {\n              _contextStorage = ((HandlerContextStorage)_contextStorage)._contextStorage;\n            }\n            else\n            {\n              _contextStorage = null;","sourceCodeStart":1431,"sourceCodeEnd":1467,"githubUrl":"https://github.com/dotnet/wpf/blob/81131a70a4c573cd62748a5c36908fc4d662daa9/src/Microsoft.DotNet.Wpf/src/WindowsBase/System/Windows/Freezable.cs#L1431-L1467","documentation":"Freezable tracks a small fixed set of event handlers (Changed, and take/protect handlers). Freezable's internal handler-removal path throws ArgumentException(SR.Freezable_UnregisteredHandler) with paramName 'handler' when asked to remove a handler that was never registered (or already removed), keeping the internal handler bookkeeping honest.","triggerScenarios":"Calling RemoveEventHandler/-= of a Changed (or internal take/protect) handler on a Freezable where that exact handler+target pair was not added, or removing it twice.","commonSituations":"Unsubscribing from Freezable.Changed with a different delegate instance than the one subscribed; disposing/unwinding logic that runs twice; cloning a Freezable expecting handlers to be copied (they generally are not).","solutions":["Keep the original delegate reference used at subscription time and pass the same instance to remove","Pair every add and remove exactly once (try/finally around usage)","Check whether the handler is registered before removing (track in your own collection)","Note that Clone does not copy Changed handlers — re-subscribe on the clone"],"exampleFix":"// before\nfreezable.Changed -= OnChanged; // may not be the registered delegate\n// after\nEventHandler handler = OnChanged;\nfreezable.Changed += handler;\n...\nfreezable.Changed -= handler;","handlingStrategy":"try-catch","validationCode":"bool subscribed = trackedHandlers.Contains(handler); if (subscribed) { freezable.Changed -= handler; trackedHandlers.Remove(handler); }","typeGuard":null,"tryCatchPattern":"try { freezable.Changed -= handler; }\ncatch (ArgumentException ex) { log.Debug(\"Handler was not registered; ignoring\", ex); }","preventionTips":["Store the exact delegate instance subscribed so the same instance is removed","Pair add/remove once with try/finally","Remember Clone() does not copy Changed handlers — resubscribe on clones"],"tags":["wpf","freezable","event-handler","argument"],"backgroundTag":"null-argument","analyzedSha":"81131a70a4c573cd62748a5c36908fc4d662daa9","analyzedAt":"2026-09-14T10:12:48.479Z","contentChangedAt":"2026-09-14T10:12:48.479Z","schemaVersion":2},"datasetVersion":"2026-09-21T21:30:21.729Z"}