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
- Snapshot the collection before mutating: iterate over a copy (e.g. columnDefinitions.Cast<ColumnDefinition>().ToArray()) so modifications don't invalidate the loop.
- Restructure code so all Add/Remove/Insert calls on ColumnDefinitions happen outside the enumeration.
- If you must mutate mid-loop, restart enumeration by fetching a fresh GetEnumerator() after each mutation.
- 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
- Never mutate ColumnDefinitions inside foreach over the same collection
- Enumerate over ToArray() copies when mutation is possible
- Defer collection changes to after the enumeration completes
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
- InvalidOperationException
- SR.Enumerator_CollectionChanged
- SR.Enumerator_CollectionChanged
- SR.Enumerator_CollectionChanged
- SR.Enumerator_CollectionChanged
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)