{"record":{"id":"73b8332681a99189","repo":"dotnet/wpf","slug":"throw-new-invalidoperationexception-sr-format-sr-73b833","errorCode":null,"errorMessage":"throw new InvalidOperationException(SR.Format(SR.AddedItemNotAtIndex, oldIndex));","messagePattern":"throw new InvalidOperationException\\(SR\\.Format\\(SR\\.AddedItemNotAtIndex, oldIndex\\)\\);","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/Microsoft.DotNet.Wpf/src/PresentationFramework/MS/Internal/Data/EnumerableCollectionView.cs","lineNumber":455,"sourceCode":"                        _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\n                    if (args.OldStartingIndex < args.NewStartingIndex)\n                    {\n                        for (int i = args.OldItems.Count - 1,\n                                oldIndex = args.OldStartingIndex + i,\n                                newIndex = args.NewStartingIndex + i;\n                            i >= 0;\n                            --i, --oldIndex, --newIndex)\n                        {\n                            if (!System.Windows.Controls.ItemsControl.EqualsEx(args.OldItems[i], _snapshot[oldIndex]))\n                                // replace error message with a better one\n                                throw new InvalidOperationException(SR.Format(SR.AddedItemNotAtIndex, oldIndex));\n                            _snapshot.Move(oldIndex, newIndex);\n                        }\n                    }\n                    else\n                    {\n                        for (int i = 0,\n                                oldIndex = args.OldStartingIndex + i,\n                                newIndex = args.NewStartingIndex + i;\n                            i < args.OldItems.Count;\n                            ++i, ++oldIndex, ++newIndex)\n                        {\n                            if (!System.Windows.Controls.ItemsControl.EqualsEx(args.OldItems[i], _snapshot[oldIndex]))\n                                // replace error message with a better one\n                                throw new InvalidOperationException(SR.Format(SR.AddedItemNotAtIndex, oldIndex));\n                            _snapshot.Move(oldIndex, newIndex);\n                        }\n                    }\n","sourceCodeStart":437,"sourceCodeEnd":473,"githubUrl":"https://github.com/dotnet/wpf/blob/81131a70a4c573cd62748a5c36908fc4d662daa9/src/Microsoft.DotNet.Wpf/src/PresentationFramework/MS/Internal/Data/EnumerableCollectionView.cs#L437-L473","documentation":"While applying a Move where the item moved forward (OldStartingIndex < NewStartingIndex), the view walks backwards verifying each moved item against its snapshot at the old index. A mismatch between args.OldItems[i] and _snapshot[oldIndex] throws AddedItemNotAtIndex because the snapshot is out of sync with the source.","triggerScenarios":"A Move event (moving items toward higher indices) whose OldItems don't match what the view previously recorded at OldStartingIndex..OldStartingIndex+Count-1.","commonSituations":"Source collection reordered itself before raising the Move event, or interleaved unreported Add/Remove calls that shifted indices; custom collection with buggy Move implementation.","solutions":["Verify the Move implementation raises the event with correct OldItems and indices before any actual mutation side effects skew them.","Raise Reset instead of Move when precise indices can't be guaranteed.","Avoid mutating the collection without raising notifications.","Refresh/rebind the view to resynchronize the snapshot."],"exampleFix":"// before\n_items.Move(oldIdx, newIdx); // but event raised with wrong OldItems\n// after\nvar moved = _items[oldIdx];\nRaiseEvent(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Move, moved, newIdx, oldIdx));\n_items.Move(oldIdx, newIdx);","handlingStrategy":"validation","validationCode":"// confirm snapshot consistency before raising Move\nif (!Equals(snapshot[oldIdx], movedItem))\n    raise Reset instead of Move;","typeGuard":null,"tryCatchPattern":"try { ApplyMove(args); } catch (InvalidOperationException) { view.Refresh(); }","preventionTips":["Raise Move events with items exactly as they existed pre-move.","Pair every mutation with a notification.","Avoid Remove+Add masquerading as Move.","Refresh the view after bulk reorders."],"tags":["wpf","inotifycollectionchanged","move","snapshot"],"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-21T21:30:21.729Z"}