dotnet/wpf · error · InvalidOperationException

SR.Freezable_UnexpectedChange

Error message

SR.Freezable_UnexpectedChange

What it means

OnCollectionChanged raises InvalidOperationException(SR.Freezable_UnexpectedChange) when it receives a NotifyCollectionChangedAction other than Add, Remove, Replace, Move, or Reset (i.e. the default/unknown action). This is an internal invariant: the WPF code constructs the args itself, so this signals a corrupted or unforeseen change action, not a caller mistake.

Solutions

  1. Audit code that constructs NotifyCollectionChangedEventArgs and always pass an explicit valid NotifyCollectionChangedAction.
  2. Do not route foreign INotifyCollectionChanged events through FreezableCollection.OnCollectionChanged.
  3. If it appears without custom code, report it as a WPF bug and capture a stack trace of the raising operation.

Example fix

// before
var args = new NotifyCollectionChangedEventArgs(default, item);
// after
var args = new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item);
Defensive patterns

Strategy: validation

Validate before calling

if (!Enum.IsDefined(typeof(NotifyCollectionChangedAction), action) || action == default)
    throw new ArgumentException("action must be an explicit NotifyCollectionChangedAction value");

Type guard

static bool IsValidAction(NotifyCollectionChangedAction a) => a is NotifyCollectionChangedAction.Add or Remove or Replace or Move or Reset;

Try / catch

try { OnCollectionChanged(args); }
catch (InvalidOperationException ex) when (ex.Message.Contains("change")) { log.Error("Unexpected change action", ex); }

Prevention

When it happens

Trigger: A change-notification pipeline (Clear, Insert, Remove, RemoveAt, AddHelper) delivering an unrecognized NotifyCollectionChangedAction to OnCollectionChanged — practically only via custom NotifyCollectionChangedEventArgs with default action or future/invalid enum values.

Common situations: Custom collection-change plumbing that builds NotifyCollectionChangedEventArgs without specifying an action, enum casting bugs, mixing WPF FreezableCollection with code assuming different enum semantics.

Understand the failure class

Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.

Related errors


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

Appendix: source

Thrown at src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/FreezableCollection.cs:754

                {
                    NotifyCollectionChangedEventArgs args;

                    switch (action)
                    {
                        case NotifyCollectionChangedAction.Reset:
                            args = new NotifyCollectionChangedEventArgs(action);
                            break;
                        case NotifyCollectionChangedAction.Add:
                            args = new NotifyCollectionChangedEventArgs(action, newValue, newIndex);
                            break;
                        case NotifyCollectionChangedAction.Remove:
                            args = new NotifyCollectionChangedEventArgs(action, oldValue, oldIndex);
                            break;
                        case NotifyCollectionChangedAction.Replace:
                            args = new NotifyCollectionChangedEventArgs(action, newValue, oldValue, newIndex);
                            break;
                        default:
                            throw new InvalidOperationException(SR.Freezable_UnexpectedChange);
                    }

                    OnCollectionChanged(args);
                }
            }
        }


        #endregion Private Helpers

        //------------------------------------------------------
        //
        //  Protected Methods
        //
        //------------------------------------------------------

        #region Protected Methods

View on GitHub (pinned to 81131a70a4)