{"record":{"id":"b5c95b1e6b98838d","repo":"dotnet/wpf","slug":"sr-enumerator-collectionchanged","errorCode":null,"errorMessage":"SR.Enumerator_CollectionChanged","messagePattern":"SR\\.Enumerator_CollectionChanged","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/FreezableCollection.cs","lineNumber":1022,"sourceCode":"            {\n                _list.ReadPreamble();\n\n                if (_version == _list._version)\n                {\n                    if (_index > -2 && _index < _list._collection.Count - 1)\n                    {\n                        _current = _list._collection[++_index];\n                        return true;\n                    }\n                    else\n                    {\n                        _index = -2; // -2 indicates \"past the end\"\n                        return false;\n                    }\n                }\n                else\n                {\n                    throw new InvalidOperationException(SR.Enumerator_CollectionChanged);\n                }\n            }\n\n            /// <summary>\n            /// Sets the enumerator to its initial position, which is before the\n            /// first element in the collection.\n            /// </summary>\n            public void Reset()\n            {\n                _list.ReadPreamble();\n\n                if (_version == _list._version)\n                {\n                    _index = -1;\n                }\n                else\n                {\n                    throw new InvalidOperationException(SR.Enumerator_CollectionChanged);","sourceCodeStart":1004,"sourceCodeEnd":1040,"githubUrl":"https://github.com/dotnet/wpf/blob/81131a70a4c573cd62748a5c36908fc4d662daa9/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/FreezableCollection.cs#L1004-L1040","documentation":"FreezableCollection<T>.Enumerator.MoveNext throws InvalidOperationException(SR.Enumerator_CollectionChanged) when the collection's version changed since the enumerator was created (_version != _list._version). Enumerators are fail-fast: any Add/Remove/Insert/RemoveAt/Clear between MoveNext calls invalidates the enumerator.","triggerScenarios":"foreach over a FreezableCollection while modifying it inside the loop body (Add/Remove/Clear), or a CollectionChanged handler mutates the collection during the same enumeration.","commonSituations":"Removing items while iterating to 'clean up', a change handler triggered mid-foreach that mutates the collection, multi-threaded access where one thread enumerates while another mutates.","solutions":["Iterate over a snapshot: foreach (var item in collection.ToList()) so mutations affect the copy.","Collect items to remove in a list, then apply Remove/RemoveAt after the loop.","For reverse-index removal loops, iterate from Count-1 down to 0 using the indexer instead of foreach.","Avoid cross-thread mutation during enumeration; synchronize access."],"exampleFix":"// before\nforeach (var item in collection)\n    if (IsBad(item)) collection.Remove(item); // throws\n// after\nforeach (var item in collection.ToList())\n    if (IsBad(item)) collection.Remove(item);","handlingStrategy":"type-guard","validationCode":"var snapshot = collection.ToList(); // version-stable copy\nforeach (var item in snapshot) { /* safe to mutate original now */ }","typeGuard":"static bool IsCurrent(Enumerator e) => !e.IsStale(); // prefer snapshot pattern instead","tryCatchPattern":"try { foreach (var item in collection) Process(item); }\ncatch (InvalidOperationException) { foreach (var item in collection.ToList()) Process(item); }","preventionTips":["Snapshot with ToList() before iterating if you may mutate","Never Add/Remove inside foreach over the same collection","Collect pending changes and apply after the loop","Synchronize cross-thread access"],"tags":["wpf","enumerator","collection-modified","fail-fast"],"backgroundTag":"collection-was-modified-during-iteration","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"}