{"record":{"id":"179ef0cedbce1eae","repo":"dotnet/wpf","slug":"invalidoperationexception-collectionviewgroupinternal","errorCode":null,"errorMessage":"InvalidOperationException","messagePattern":"InvalidOperationException","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/Microsoft.DotNet.Wpf/src/PresentationFramework/MS/Internal/Data/CollectionViewGroupInternal.cs","lineNumber":776,"sourceCode":"            }\n\n            void IEnumerator.Reset()\n            {\n                DoReset();\n            }\n\n            private void DoReset()\n            {\n                _version = _group._version;\n                _index = -1;\n                _subEnum = null;\n            }\n\n            bool IEnumerator.MoveNext()\n            {\n                // check for invalidated enumerator\n                if (_group._version != _version)\n                    throw new InvalidOperationException();\n\n                // move forward to the next leaf\n                while (_subEnum == null || !_subEnum.MoveNext())\n                {\n                    // done with the current top-level item.  Move to the next one.\n                    ++_index;\n                    if (_index >= _group.Items.Count)\n                        return false;\n\n                    CollectionViewGroupInternal subgroup = _group.Items[_index] as CollectionViewGroupInternal;\n                    if (subgroup == null)\n                    {\n                        // current item is a leaf - it's the new Current\n                        _current = _group.Items[_index];\n                        _subEnum = null;\n                        return true;\n                    }\n                    else","sourceCodeStart":758,"sourceCodeEnd":794,"githubUrl":"https://github.com/dotnet/wpf/blob/81131a70a4c573cd62748a5c36908fc4d662daa9/src/Microsoft.DotNet.Wpf/src/PresentationFramework/MS/Internal/Data/CollectionViewGroupInternal.cs#L758-L794","documentation":"LeafEnumerator detects that its parent group was modified (version bump) after enumeration started, and MoveNext throws a bare InvalidOperationException. Enumerators over grouped collection views are invalidated by structural changes to the group.","triggerScenarios":"Continuing a foreach over a group's leaves after adding/removing/moving items in the grouped source (or regrouping) mid-enumeration.","commonSituations":"Modifying the ObservableCollection in a CollectionChanged handler while UI enumerates groups; enumerating on a background thread while UI thread refreshes the view; deferred LINQ evaluation over stale group enumerators.","solutions":["Snapshot the leaves (e.g. ToList()) before mutating or holding the enumerator","Make collection changes after enumeration completes, or re-enumerate after changes","Avoid mutating the grouped source from within enumeration; defer via Dispatcher.BeginInvoke"],"exampleFix":"// before\nforeach (var leaf in group.Leaves) items.Remove(leaf);\n// after\nvar snapshot = group.Leaves.Cast<object>().ToList();\nforeach (var leaf in snapshot) items.Remove(leaf);","handlingStrategy":"try-catch","validationCode":"if (group._version != capturedVersion) { enumerator = group.GetLeafEnumerator(); }","typeGuard":null,"tryCatchPattern":"try { while (e.MoveNext()) { /* ... */ } } catch (InvalidOperationException) { e = group.GetLeafEnumerator(); /* re-enumerate */ }","preventionTips":["Snapshot group leaves before mutating","Never modify the grouped source inside a foreach over it","Re-create enumerators after refresh/regroup"],"tags":["wpf","collectionview","enumerator","collection-modified"],"backgroundTag":"invalid-state-transition","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"}