dotnet/wpf · error · ArgumentOutOfRangeException

ArgumentOutOfRangeException

Error message

ArgumentOutOfRangeException

What it means

CollectionViewGroupInternal.LeafAt walks the group tree to locate the leaf at a given index; if the loop finishes without finding it, it throws ArgumentOutOfRangeException(nameof(index)), an internal invariant that the requested leaf index is outside the group's leaf range.

Solutions

  1. Ensure all source collection mutations happen on the UI thread or via INotifyCollectionChanged
  2. Re-fetch the collection view / refresh grouping after mutating data
  3. Bounds-check index against the view's Count before indexing

Example fix

// before
var item = groupedView.Items[view.Count - 1 + 1]; // stale count
// after
int i = view.Count - 1;
if (i >= 0) var item = groupedView.Items[i];
Defensive patterns

Strategy: validation

Validate before calling

if (index >= 0 && index < view.Count) { var item = view.GetItemAt(index); }

Type guard

bool LeafIndexExists(ICollectionView view, int i) => i >= 0 && i < view.Count;

Try / catch

try { var item = group.LeafAt(index); } catch (ArgumentOutOfRangeException) { /* group changed; re-fetch view */ }

Prevention

When it happens

Trigger: Requesting a leaf index >= total leaf count of the group, typically via collection view indexing after the group contents changed without the view being notified.

Common situations: Accessing ItemsControl items or CollectionView[i] after mutating grouped source collection off the UI thread; stale snapshots of groups; custom views bypassing change notification.

Related errors


AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14). Data as JSON: /api/errors/b4bb0c08582f55f8. Report an issue: GitHub.

Appendix: source

Thrown at src/Microsoft.DotNet.Wpf/src/PresentationFramework/MS/Internal/Data/CollectionViewGroupInternal.cs:351

                        index -= subgroup.ItemCount;
                    }
                }
                else
                {
                    // current item is a leaf - see if we're done
                    if (index == 0)
                    {
                        return Items[k];
                    }
                    else
                    {
                        index -= 1;
                    }
                }
            }

            // the loop should have found the index.  We shouldn't get here.
            throw new ArgumentOutOfRangeException(nameof(index));
        }

        // return an enumerator over the leaves governed by this group
        internal IEnumerator GetLeafEnumerator()
        {
            return new LeafEnumerator(this);
        }

        // insert a new item or subgroup and return its index.  Seed is a
        // representative from the subgroup (or the item itself) that
        // is used to position the new item/subgroup w.r.t. the order given
        // by the comparer.  (If comparer is null, just add at the end).
        internal int Insert(object item, object seed, IComparer comparer)
        {
            // when group sorting is not declared,
            // never insert the new item/group before the explicit subgroups
            int low = 0;
            if (_groupComparer == null && GroupBy != null)

View on GitHub (pinned to 81131a70a4)