dotnet/wpf · error · InvalidOperationException

throw new…

Error message

throw new InvalidOperationException(SR.Format(SR.AddedItemNotAtIndex, oldIndex));

What it means

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.

Solutions

  1. Verify the Move implementation raises the event with correct OldItems and indices before any actual mutation side effects skew them.
  2. Raise Reset instead of Move when precise indices can't be guaranteed.
  3. Avoid mutating the collection without raising notifications.
  4. Refresh/rebind the view to resynchronize the snapshot.

Example fix

// before
_items.Move(oldIdx, newIdx); // but event raised with wrong OldItems
// after
var moved = _items[oldIdx];
RaiseEvent(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Move, moved, newIdx, oldIdx));
_items.Move(oldIdx, newIdx);
Defensive patterns

Strategy: validation

Validate before calling

// confirm snapshot consistency before raising Move
if (!Equals(snapshot[oldIdx], movedItem))
    raise Reset instead of Move;

Try / catch

try { ApplyMove(args); } catch (InvalidOperationException) { view.Refresh(); }

Prevention

When it happens

Trigger: A Move event (moving items toward higher indices) whose OldItems don't match what the view previously recorded at OldStartingIndex..OldStartingIndex+Count-1.

Common situations: Source collection reordered itself before raising the Move event, or interleaved unreported Add/Remove calls that shifted indices; custom collection with buggy Move implementation.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


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

Appendix: source

Thrown at src/Microsoft.DotNet.Wpf/src/PresentationFramework/MS/Internal/Data/EnumerableCollectionView.cs:455

                        _snapshot[index] = args.NewItems[i];
                    }
                    break;

                case NotifyCollectionChangedAction.Move:
                    if (args.NewStartingIndex < 0)
                        throw new InvalidOperationException(SR.CannotMoveToUnknownPosition);

                    if (args.OldStartingIndex < args.NewStartingIndex)
                    {
                        for (int i = args.OldItems.Count - 1,
                                oldIndex = args.OldStartingIndex + i,
                                newIndex = args.NewStartingIndex + i;
                            i >= 0;
                            --i, --oldIndex, --newIndex)
                        {
                            if (!System.Windows.Controls.ItemsControl.EqualsEx(args.OldItems[i], _snapshot[oldIndex]))
                                // replace error message with a better one
                                throw new InvalidOperationException(SR.Format(SR.AddedItemNotAtIndex, oldIndex));
                            _snapshot.Move(oldIndex, newIndex);
                        }
                    }
                    else
                    {
                        for (int i = 0,
                                oldIndex = args.OldStartingIndex + i,
                                newIndex = args.NewStartingIndex + i;
                            i < args.OldItems.Count;
                            ++i, ++oldIndex, ++newIndex)
                        {
                            if (!System.Windows.Controls.ItemsControl.EqualsEx(args.OldItems[i], _snapshot[oldIndex]))
                                // replace error message with a better one
                                throw new InvalidOperationException(SR.Format(SR.AddedItemNotAtIndex, oldIndex));
                            _snapshot.Move(oldIndex, newIndex);
                        }
                    }

View on GitHub (pinned to 81131a70a4)