{"record":{"id":"b4bb0c08582f55f8","repo":"dotnet/wpf","slug":"argumentoutofrangeexception-collectionviewgroupinternal","errorCode":null,"errorMessage":"ArgumentOutOfRangeException","messagePattern":"ArgumentOutOfRangeException","errorType":"exception","errorClass":"ArgumentOutOfRangeException","httpStatus":null,"severity":"error","filePath":"src/Microsoft.DotNet.Wpf/src/PresentationFramework/MS/Internal/Data/CollectionViewGroupInternal.cs","lineNumber":351,"sourceCode":"                        index -= subgroup.ItemCount;\n                    }\n                }\n                else\n                {\n                    // current item is a leaf - see if we're done\n                    if (index == 0)\n                    {\n                        return Items[k];\n                    }\n                    else\n                    {\n                        index -= 1;\n                    }\n                }\n            }\n\n            // the loop should have found the index.  We shouldn't get here.\n            throw new ArgumentOutOfRangeException(nameof(index));\n        }\n\n        // return an enumerator over the leaves governed by this group\n        internal IEnumerator GetLeafEnumerator()\n        {\n            return new LeafEnumerator(this);\n        }\n\n        // insert a new item or subgroup and return its index.  Seed is a\n        // representative from the subgroup (or the item itself) that\n        // is used to position the new item/subgroup w.r.t. the order given\n        // by the comparer.  (If comparer is null, just add at the end).\n        internal int Insert(object item, object seed, IComparer comparer)\n        {\n            // when group sorting is not declared,\n            // never insert the new item/group before the explicit subgroups\n            int low = 0;\n            if (_groupComparer == null && GroupBy != null)","sourceCodeStart":333,"sourceCodeEnd":369,"githubUrl":"https://github.com/dotnet/wpf/blob/81131a70a4c573cd62748a5c36908fc4d662daa9/src/Microsoft.DotNet.Wpf/src/PresentationFramework/MS/Internal/Data/CollectionViewGroupInternal.cs#L333-L369","documentation":"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.","triggerScenarios":"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.","commonSituations":"Accessing ItemsControl items or CollectionView[i] after mutating grouped source collection off the UI thread; stale snapshots of groups; custom views bypassing change notification.","solutions":["Ensure all source collection mutations happen on the UI thread or via INotifyCollectionChanged","Re-fetch the collection view / refresh grouping after mutating data","Bounds-check index against the view's Count before indexing"],"exampleFix":"// before\nvar item = groupedView.Items[view.Count - 1 + 1]; // stale count\n// after\nint i = view.Count - 1;\nif (i >= 0) var item = groupedView.Items[i];","handlingStrategy":"validation","validationCode":"if (index >= 0 && index < view.Count) { var item = view.GetItemAt(index); }","typeGuard":"bool LeafIndexExists(ICollectionView view, int i) => i >= 0 && i < view.Count;","tryCatchPattern":"try { var item = group.LeafAt(index); } catch (ArgumentOutOfRangeException) { /* group changed; re-fetch view */ }","preventionTips":["Bounds-check against the view's Count before indexing","Mutate grouped sources only on the UI thread","Refresh the view after bulk data changes"],"tags":["wpf","collectionview","grouping","argument-out-of-range"],"backgroundTag":"index-out-of-bounds","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"}