dotnet/wpf · error · InvalidOperationException

SR.EnumeratorVersionChanged

Error message

SR.EnumeratorVersionChanged

What it means

ColumnDefinition.ColumnDefinitionCollection's enumerator detects that the collection's internal version counter no longer matches the version captured when the enumerator was created. WPF collections invalidate enumerators whenever the collection is modified, so continuing to enumerate after Add/Remove/Clear throws InvalidOperationException(SR.EnumeratorVersionChanged). This protects against undefined behavior from a mutated underlying list.

Solutions

  1. Snapshot the collection before mutating: iterate over a copy (e.g. columnDefinitions.Cast<ColumnDefinition>().ToArray()) so modifications don't invalidate the loop.
  2. Restructure code so all Add/Remove/Insert calls on ColumnDefinitions happen outside the enumeration.
  3. If you must mutate mid-loop, restart enumeration by fetching a fresh GetEnumerator() after each mutation.
  4. Catch InvalidOperationException around MoveNext/Reset only when invalidation is expected and acceptable.

Example fix

// before
foreach (ColumnDefinition cd in grid.ColumnDefinitions)
{
    if (cd.Width.IsAuto) grid.ColumnDefinitions.Remove(cd); // throws
}
// after
foreach (ColumnDefinition cd in grid.ColumnDefinitions.ToArray())
{
    if (cd.Width.IsAuto) grid.ColumnDefinitions.Remove(cd);
}
Defensive patterns

Strategy: try-catch

Validate before calling

var snapshot = grid.ColumnDefinitions.Cast<ColumnDefinition>().ToArray();
bool canEnumerate = snapshot.Length == grid.ColumnDefinitions.Count;

Type guard

static bool IsEnumerationValid(ColumnDefinitionCollection c, int knownVersionCount) => c.Count == knownVersionCount;

Try / catch

try
{
    foreach (ColumnDefinition cd in grid.ColumnDefinitions) { /* ... */ }
}
catch (InvalidOperationException)
{
    // collection changed mid-enumeration; restart with a snapshot
}

Prevention

When it happens

Trigger: Calling MoveNext() or Reset() on a ColumnDefinitionCollection enumerator after the collection was structurally modified (adding/removing ColumnDefinitions, Clear()) since the enumerator was obtained (e.g. modifying Grid.ColumnDefinitions inside a foreach over it).

Common situations: Dynamically adding columns to a Grid inside a foreach loop, a PropertyChanged/data-binding handler that mutates ColumnDefinitions while UI code is enumerating them, or sharing an enumerator across code that re-lays-out the grid.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


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

Appendix: source

Thrown at src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Controls/ColumnDefinition.cs:924

            public void Dispose()
            {
                _currentElement = null;
            }

            /// <summary>
            ///     Validates that
            ///     enumerator is not disposed;
            ///     enumerator is still in sync with collection;
            /// </summary>
            private void PrivateValidate()
            {
                if (_currentElement == null)
                {
                    throw new InvalidOperationException(SR.EnumeratorCollectionDisposed);
                }
                if (_version != _collection._version)
                {
                    throw new InvalidOperationException(SR.EnumeratorVersionChanged);
                }
            }

            private ColumnDefinitionCollection _collection;              //  the collection to be enumerated
            private int _index;                         //  current element index
            private int _version;                       //  the snapshot of collection's version at the time of creation
            private object _currentElement;             //  multipurpose:
                                                        //  points to the collection object when enumerator is either before start or after end
                                                        //  points to the current element while in the process of enumeration
                                                        //  is null if disposed
        }

        #endregion Private Structures Classes
    }

    /// <summary>
    ///     ColumnDefinition is a FrameworkContentElement used by Grid
    ///     to hold column / row specific properties.

View on GitHub (pinned to 81131a70a4)