{"record":{"id":"dc36f7ffc11cc8b8","repo":"dotnet/wpf","slug":"throw-new-invalidoperationexception-sr-format-sr-dc36f7","errorCode":null,"errorMessage":"throw new InvalidOperationException(SR.Format(SR.AddedItemNotAtIndex, index));","messagePattern":"throw new InvalidOperationException\\(SR\\.Format\\(SR\\.AddedItemNotAtIndex, index\\)\\);","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/Microsoft.DotNet.Wpf/src/PresentationFramework/MS/Internal/Data/EnumerableCollectionView.cs","lineNumber":426,"sourceCode":"                    }\n                    else\n                    {   // insert\n                        for (int i = args.NewItems.Count - 1; i >= 0; --i)\n                        {\n                            _snapshot.Insert(args.NewStartingIndex, args.NewItems[i]);\n                        }\n                    }\n                    break;\n\n                case NotifyCollectionChangedAction.Remove:\n                    if (args.OldStartingIndex < 0)\n                        throw new InvalidOperationException(SR.RemovedItemNotFound);\n\n                    for (int i = args.OldItems.Count - 1, index = args.OldStartingIndex + i; i >= 0; --i, --index)\n                    {\n                        if (!System.Windows.Controls.ItemsControl.EqualsEx(args.OldItems[i], _snapshot[index]))\n                            // replace error message with a better one\n                            throw new InvalidOperationException(SR.Format(SR.AddedItemNotAtIndex, index));\n                        _snapshot.RemoveAt(index);\n                    }\n                    break;\n\n                case NotifyCollectionChangedAction.Replace:\n                    for (int i = args.NewItems.Count - 1, index = args.NewStartingIndex + i; i >= 0; --i, --index)\n                    {\n                        if (!System.Windows.Controls.ItemsControl.EqualsEx(args.OldItems[i], _snapshot[index]))\n                            // replace error message with a better one\n                            throw new InvalidOperationException(SR.Format(SR.AddedItemNotAtIndex, index));\n                        _snapshot[index] = args.NewItems[i];\n                    }\n                    break;\n\n                case NotifyCollectionChangedAction.Move:\n                    if (args.NewStartingIndex < 0)\n                        throw new InvalidOperationException(SR.CannotMoveToUnknownPosition);\n","sourceCodeStart":408,"sourceCodeEnd":444,"githubUrl":"https://github.com/dotnet/wpf/blob/81131a70a4c573cd62748a5c36908fc4d662daa9/src/Microsoft.DotNet.Wpf/src/PresentationFramework/MS/Internal/Data/EnumerableCollectionView.cs#L408-L444","documentation":"While processing a Remove notification, EnumerableCollectionView verifies that the item reported as removed actually sits at the expected index in its internal snapshot before deleting it. If _snapshot[index] does not equal args.OldItems[i] (via ItemsControl.EqualsEx), the snapshot and source collection have diverged and AddedItemNotAtIndex is thrown.","triggerScenarios":"Source collection raised Remove with OldStartingIndex pointing at an item that differs from args.OldItems[i] in the view's snapshot — e.g. the source mutated its items without raising corresponding notifications, or raised events out of order.","commonSituations":"Custom collection that changes item order or content without raising change notifications while an ItemsControl is bound; missed events because the collection was modified before the view subscribed.","solutions":["Ensure every mutation of the source collection raises a matching, correctly-indexed CollectionChanged event.","Make item equality (EqualsEx uses Equals) stable — don't mutate items' identity fields used by Equals.","Raise Reset for bulk mutations so the view rebuilds its snapshot.","Force a Refresh/rebind of the view to resynchronize the snapshot."],"exampleFix":"// before\n_items[0] = newItem; // silent mutation, later Remove at 0 mismatches snapshot\n// after\n_items[0] = newItem;\nOnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, newItem, oldItem, 0));","handlingStrategy":"validation","validationCode":"// before raising Remove, verify the item is still at the reported index\nif (!Equals(collection[oldStartingIndex], removedItem))\n    collectionChangedArgs = new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset);","typeGuard":null,"tryCatchPattern":"// recover by forcing a rebuild\ntry { ProcessChange(args); } catch (InvalidOperationException) { view.Refresh(); }","preventionTips":["Capture OldItems before mutating the underlying list.","Never mutate collection contents without raising notifications.","Use stable Equals semantics on items.","Raise Reset when indices can't be guaranteed."],"tags":["wpf","inotifycollectionchanged","snapshot","out-of-sync"],"backgroundTag":"internal-invariant-violation","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"}