dotnet/wpf · error · InvalidOperationException
SR.Enumerator_CollectionChanged
Error message
SR.Enumerator_CollectionChanged
What it means
Model3DCollection's strongly-typed enumerator throws InvalidOperationException(SR.Enumerator_CollectionChanged) from MoveNext when the collection's version counter changed since enumeration started. WPF enumerators are fail-fast: any Add/Remove/Insert during a foreach invalidates the enumerator. The _index == -2 sentinel indicates past-the-end state handled separately; this throw is the mid-enumeration mutation case.
Solutions
- Snapshot before iterating: foreach (var m in collection.ToArray()) so mutation of the original is safe.
- Collect items to remove/add in a temporary list, then apply the changes after the loop.
- If multithreaded, marshal all collection mutations to the UI (dispatcher) thread and never enumerate while another thread mutates.
Example fix
// before
foreach (var m in collection)
{
if (ShouldRemove(m)) collection.Remove(m); // InvalidOperationException
}
// after
foreach (var m in collection.ToArray())
{
if (ShouldRemove(m)) collection.Remove(m);
} Defensive patterns
Strategy: try-catch
Validate before calling
int v0 = collection.Count; // capture; if you cannot guarantee no mutation, snapshot var snapshot = collection.ToArray();
Try / catch
try { foreach (var m in collection) { /* ... */ } } catch (InvalidOperationException ex) when (ex.Message.Contains("CollectionChanged")) { // retry with a snapshot
foreach (var m in collection.ToArray()) { /* ... */ } } Prevention
- Never mutate a WPF collection while enumerating it
- Buffer changes in a temp list and apply after the loop
- Use ToArray() snapshots when handlers may mutate the collection
- Keep collection access single-threaded (UI thread)
When it happens
Trigger: Modifying the Model3DCollection (Add, Remove, Insert, Clear, indexer set) between MoveNext calls inside a foreach or while advancing the enumerator manually.
Common situations: Removing a model from the collection in response to a property change triggered while iterating; UI-event handlers mutating the collection during enumeration; background threads touching the collection while the UI thread enumerates.
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.Enumerator_CollectionChanged
- SR.Enumerator_CollectionChanged
- SR.Enumerator_NotStarted
- Cannot pass multidimensional array to the CopyTo method on…
AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14).
Data as JSON: /api/errors/9e6c11cb9b4e32a7.
Report an issue: GitHub.
Appendix: source
Thrown at src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media3D/Generated/Model3DCollection.cs:830
{
_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)