dotnet/wpf · error · InvalidOperationException

SR.Enumerator_CollectionChanged

Error message

SR.Enumerator_CollectionChanged

What it means

Point3DCollection's enumerator MoveNext throws InvalidOperationException(SR.Enumerator_CollectionChanged) when the collection's version changed since the enumerator was created. The enumerator compares its cached _version against the list's _version and invalidates itself to guarantee fail-fast enumeration.

Solutions

  1. Do not modify the collection while enumerating; enumerate a snapshot copy (ToList) if you must mutate
  2. Collect items to remove into a separate list and apply changes after the loop
  3. Use a for loop over indices with care, or lock if cross-thread access is possible

Example fix

// before
foreach (Point3D p in collection)
    if (p.X == 0) collection.Remove(p); // throws on next MoveNext
// after
foreach (Point3D p in collection.ToList())
    if (p.X == 0) collection.Remove(p);
Defensive patterns

Strategy: try-catch

Validate before calling

// no pre-call check possible; version is internal. Snapshot instead:
var snapshot = collection.ToList(); // enumerate snapshot if mutation is expected

Try / catch

try { foreach (var p in collection) { /* ... */ } }
catch (InvalidOperationException) { /* collection changed during enumeration; retry with snapshot */ foreach (var p in collection.ToList()) { } }

Prevention

When it happens

Trigger: Calling MoveNext() on an enumerator after any Add/Remove/Clear (or other version-bumping mutation) on the owning Point3DCollection between GetEnumerator() and MoveNext.

Common situations: Modifying the collection inside a foreach loop; another thread/UI handler mutating the collection during enumeration; enumerating while a deferred animation or data binding updates the list.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


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

Appendix: source

Thrown at src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media3D/Generated/Point3DCollection.cs:816

            {
                _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)