dotnet/wpf · error · InvalidOperationException
InvalidOperationException
Error message
InvalidOperationException
What it means
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.
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
Example fix
// before foreach (var leaf in group.Leaves) items.Remove(leaf); // after var snapshot = group.Leaves.Cast<object>().ToList(); foreach (var leaf in snapshot) items.Remove(leaf);
Defensive patterns
Strategy: try-catch
Validate before calling
if (group._version != capturedVersion) { enumerator = group.GetLeafEnumerator(); } Try / catch
try { while (e.MoveNext()) { /* ... */ } } catch (InvalidOperationException) { e = group.GetLeafEnumerator(); /* re-enumerate */ } Prevention
- Snapshot group leaves before mutating
- Never modify the grouped source inside a foreach over it
- Re-create enumerators after refresh/regroup
When it happens
Trigger: Continuing a foreach over a group's leaves after adding/removing/moving items in the grouped source (or regrouping) mid-enumeration.
Common situations: 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.
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.EnumeratorVersionChanged
- 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/179ef0cedbce1eae.
Report an issue: GitHub.
Appendix: source
Thrown at src/Microsoft.DotNet.Wpf/src/PresentationFramework/MS/Internal/Data/CollectionViewGroupInternal.cs:776
}
void IEnumerator.Reset()
{
DoReset();
}
private void DoReset()
{
_version = _group._version;
_index = -1;
_subEnum = null;
}
bool IEnumerator.MoveNext()
{
// check for invalidated enumerator
if (_group._version != _version)
throw new InvalidOperationException();
// move forward to the next leaf
while (_subEnum == null || !_subEnum.MoveNext())
{
// done with the current top-level item. Move to the next one.
++_index;
if (_index >= _group.Items.Count)
return false;
CollectionViewGroupInternal subgroup = _group.Items[_index] as CollectionViewGroupInternal;
if (subgroup == null)
{
// current item is a leaf - it's the new Current
_current = _group.Items[_index];
_subEnum = null;
return true;
}
elseView on GitHub (pinned to 81131a70a4)