dotnet/wpf · error · InvalidOperationException
throw new…
Error message
throw new InvalidOperationException(SR.EnumeratorVersionChanged);
What it means
CompositeCollectionView's inner enumerator caches the collection version at creation. CheckVersion() compares the cached version against the collection's current _version, which is bumped on every collection change (Refresh, add/remove, etc.). If the collection was modified after enumeration started, the enumerator is stale and this InvalidOperationException is thrown.
Solutions
- Finish enumerating before modifying the collection, or collect items into a list first and iterate the snapshot.
- Re-acquire a fresh enumerator (call GetEnumerator again) after modifying the collection.
- If cross-thread modification is involved, marshal all collection changes to the thread that owns the collection (Dispatcher.BeginInvoke).
- Catch InvalidOperationException and restart iteration with a new enumerator if a stale-enumeration retry is acceptable.
Example fix
// before
foreach (var item in compositeCollection) { if (cond) compositeCollection.Remove(item); }
// after
var snapshot = compositeCollection.Cast<object>().ToList();
foreach (var item in snapshot) { if (cond) compositeCollection.Remove(item); } Defensive patterns
Strategy: try-catch
Try / catch
// snapshot before mutating
var items = compositeCollection.Cast<object>().ToList();
foreach (var item in items) { /* safe iteration */ } Prevention
- Never modify a CompositeCollection while an enumerator from it is alive.
- Snapshot items with ToList() before filtering/removing.
- Marshal collection mutations to the owning UI thread.
- Re-fetch the enumerator after any change or Refresh().
When it happens
Trigger: Calling MoveNext() or MoveNextOrDefault() on a CompositeCollection's enumerator (via IEnumerator) after the CompositeCollection or its underlying views/collections raised a change that invalidated the view (_isInvalidated set or _version changed).
Common situations: Iterating a CompositeCollection bound to UI in a foreach loop while the collection is modified on another thread, in a CollectionChanged handler, or via data binding refresh; holding an enumerator across a Refresh() call.
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/6581699b35b9f277.
Report an issue: GitHub.
Appendix: source
Thrown at src/Microsoft.DotNet.Wpf/src/PresentationFramework/MS/Internal/Data/CompositeCollectionView.cs:1593
public void Dispose()
{
DisposeContainerEnumerator();
}
private void DisposeContainerEnumerator()
{
IDisposable d = _containerEnumerator as IDisposable;
d?.Dispose();
_containerEnumerator = null;
}
private void CheckVersion()
{
// note: there's a very unlikely possibility that the
// version number wraps around back to the same number
if (_isInvalidated || (_isInvalidated = (_version != _view._version)))
throw new InvalidOperationException(SR.EnumeratorVersionChanged);
}
private CompositeCollection _collection;
private CompositeCollectionView _view;
private int _index;
private object _current;
private IEnumerator _containerEnumerator;
private bool _done;
private bool _isInvalidated = false;
private int _version;
}
#endregion Private Types
//------------------------------------------------------
//
// Private FieldsView on GitHub (pinned to 81131a70a4)