dotnet/wpf · error · InvalidOperationException

SR.Enumerator_CollectionChanged

Error message

SR.Enumerator_CollectionChanged

What it means

VectorCollection's enumerator stores the collection's _version when created; MoveNext compares versions on each advance. If the collection was modified (Add, Remove, Clear, Insert, Set) after the enumerator was obtained, MoveNext throws InvalidOperationException (Enumerator_CollectionChanged). This is standard fail-fast enumerator invalidation protecting against iterating a mutated list.

Solutions

  1. Do not modify the collection inside the foreach; collect pending changes in a temporary list and apply them after the loop.
  2. Iterate over a snapshot: `foreach (var v in vectorCollection.ToArray())` so mutation of the original is safe.
  3. If modification is required mid-loop, break out, mutate, then obtain a fresh enumerator via a new foreach.
  4. Synchronize access so no other thread/event mutates the collection during iteration.

Example fix

// before
foreach (Vector v in vectorCollection) { if (v.Length == 0) vectorCollection.Remove(v); } // throws
// after
foreach (Vector v in vectorCollection.ToArray()) { if (v.Length == 0) vectorCollection.Remove(v); }
Defensive patterns

Strategy: try-catch

Try / catch

var snapshot = vectorCollection.ToArray();
foreach (var v in snapshot)
{
    try { /* mutate vectorCollection if needed */ }
    catch (InvalidOperationException ex) when (ex.Message.Contains("changed"))
    {
        // restart iteration with a fresh enumerator
    }
}

Prevention

When it happens

Trigger: Calling MoveNext() (explicitly or via foreach) on a VectorCollection enumerator after any structural modification of the same collection since GetEnumerator() was called.

Common situations: Adding/removing vectors inside a foreach over a VectorCollection; modifying the collection from another thread or event handler (e.g. Animation/Render callbacks) while a loop is in progress; calling Clear() then continuing to iterate a stale enumerator.

Related errors


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

Appendix: source

Thrown at src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/Generated/VectorCollection.cs:817

            {
                _list.ReadPreamble();

                if (_version == _list._version)
                {
                    if (_index > -2 && _index < _list._collection.Count - 1)
                    {
                        _current = _list._collection[++_index];
                        return true;
                    }
                    else
                    {
                        _index = -2; // -2 indicates "past the end"
                        return false;
                    }
                }
                else
                {
                    throw new InvalidOperationException(SR.Enumerator_CollectionChanged);
                }
            }

            /// <summary>
            /// Sets the enumerator to its initial position, which is before the
            /// first element in the collection.
            /// </summary>
            public void Reset()
            {
                _list.ReadPreamble();

                if (_version == _list._version)
                {
                    _index = -1;
                }
                else
                {
                    throw new InvalidOperationException(SR.Enumerator_CollectionChanged);

View on GitHub (pinned to 81131a70a4)