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
- Do not modify the collection while enumerating; enumerate a snapshot copy (ToList) if you must mutate
- Collect items to remove into a separate list and apply changes after the loop
- 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
- Never mutate a Point3DCollection during foreach
- Collect mutations in a pending list and apply after the loop
- Snapshot with ToList() when another thread or binding may mutate
- Re-enumerate after any modification instead of reusing enumerators
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
- SR.Enumerator_CollectionChanged
- SR.Timing_EnumeratorInvalidated
- InvalidOperationException
- SR.Enumerator_CollectionChanged
- SR.Enumerator_CollectionChanged
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)