{"record":{"id":"6581699b35b9f277","repo":"dotnet/wpf","slug":"throw-new-invalidoperationexception-sr-658169","errorCode":null,"errorMessage":"throw new InvalidOperationException(SR.EnumeratorVersionChanged);","messagePattern":"throw new InvalidOperationException\\(SR\\.EnumeratorVersionChanged\\);","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/Microsoft.DotNet.Wpf/src/PresentationFramework/MS/Internal/Data/CompositeCollectionView.cs","lineNumber":1593,"sourceCode":"            public void Dispose()\n            {\n                DisposeContainerEnumerator();\n            }\n\n            private void DisposeContainerEnumerator()\n            {\n                IDisposable d = _containerEnumerator as IDisposable;\n                d?.Dispose();\n\n                _containerEnumerator = null;\n            }\n\n            private void CheckVersion()\n            {\n                // note: there's a very unlikely possibility that the\n                // version number wraps around back to the same number\n                if (_isInvalidated || (_isInvalidated = (_version != _view._version)))\n                    throw new InvalidOperationException(SR.EnumeratorVersionChanged);\n            }\n\n            private CompositeCollection _collection;\n            private CompositeCollectionView _view;\n            private int _index;\n            private object _current;\n            private IEnumerator _containerEnumerator;\n            private bool _done;\n            private bool _isInvalidated = false;\n            private int _version;\n        }\n\n        #endregion Private Types\n\n\n        //------------------------------------------------------\n        //\n        //  Private Fields","sourceCodeStart":1575,"sourceCodeEnd":1611,"githubUrl":"https://github.com/dotnet/wpf/blob/81131a70a4c573cd62748a5c36908fc4d662daa9/src/Microsoft.DotNet.Wpf/src/PresentationFramework/MS/Internal/Data/CompositeCollectionView.cs#L1575-L1611","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","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."],"exampleFix":"// before\nforeach (var item in compositeCollection) { if (cond) compositeCollection.Remove(item); }\n// after\nvar snapshot = compositeCollection.Cast<object>().ToList();\nforeach (var item in snapshot) { if (cond) compositeCollection.Remove(item); }","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"// snapshot before mutating\nvar items = compositeCollection.Cast<object>().ToList();\nforeach (var item in items) { /* safe iteration */ }","preventionTips":["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()."],"tags":["wpf","collection-view","enumerator","collection-modified"],"backgroundTag":"collection-modified-during-enumeration","analyzedSha":"81131a70a4c573cd62748a5c36908fc4d662daa9","analyzedAt":"2026-09-14T10:12:48.479Z","contentChangedAt":"2026-09-14T10:12:48.479Z","schemaVersion":2},"datasetVersion":"2026-09-22T01:17:13.364Z"}