dotnet/wpf · error · ArgumentException

SR.Freezable_UnregisteredHandler

Error message

SR.Freezable_UnregisteredHandler

What it means

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.

Solutions

  1. Keep the original delegate reference used at subscription time and pass the same instance to remove
  2. Pair every add and remove exactly once (try/finally around usage)
  3. Check whether the handler is registered before removing (track in your own collection)
  4. Note that Clone does not copy Changed handlers — re-subscribe on the clone

Example fix

// before
freezable.Changed -= OnChanged; // may not be the registered delegate
// after
EventHandler handler = OnChanged;
freezable.Changed += handler;
...
freezable.Changed -= handler;
Defensive patterns

Strategy: try-catch

Validate before calling

bool subscribed = trackedHandlers.Contains(handler); if (subscribed) { freezable.Changed -= handler; trackedHandlers.Remove(handler); }

Try / catch

try { freezable.Changed -= handler; }
catch (ArgumentException ex) { log.Debug("Handler was not registered; ignoring", ex); }

Prevention

When it happens

Trigger: 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.

Common situations: 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).

Related errors


AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14). Data as JSON: /api/errors/99adc4e5f9869e7d. Report an issue: GitHub.

Appendix: source

Thrown at src/Microsoft.DotNet.Wpf/src/WindowsBase/System/Windows/Freezable.cs:1449

            {
                FrugalObjectList<EventHandler> handlers = HandlerList;
                int index = handlers.IndexOf(handler);

                if (index >= 0)
                {
                    handlers.RemoveAt(index);
                    failed = false;
                }

                if (handlers.Count == 0)
                {
                    RemoveHandlerList();
                }
            }

            if (failed)
            {
                throw new ArgumentException(SR.Freezable_UnregisteredHandler, nameof(handler));
            }
        }

        //
        //  Removes the singleton handler the Freezable is storing and resets
        //  any state indicating this.
        //
        private void RemoveSingletonHandler()
        {
            Debug.Assert(Freezable_UsingSingletonHandler);

            if (HasContextInformation)
            {
              _contextStorage = ((HandlerContextStorage)_contextStorage)._contextStorage;
            }
            else
            {
              _contextStorage = null;

View on GitHub (pinned to 81131a70a4)