dotnet/wpf · error · InvalidOperationException
throw new…
Error message
throw new InvalidOperationException(SR.Format(SR.AddedItemNotAtIndex, index));
What it means
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.
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.
Example fix
// before _items[0] = newItem; // silent mutation, later Remove at 0 mismatches snapshot // after _items[0] = newItem; OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, newItem, oldItem, 0));
Defensive patterns
Strategy: validation
Validate before calling
// before raising Remove, verify the item is still at the reported index
if (!Equals(collection[oldStartingIndex], removedItem))
collectionChangedArgs = new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset); Try / catch
// recover by forcing a rebuild
try { ProcessChange(args); } catch (InvalidOperationException) { view.Refresh(); } Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
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
- throw new…
- SR.Format(SR.UnexpectedCollectionChangeAction, args.Action)
- SR.Format(SR.UnexpectedCollectionChangeAction, e.Action)
- SR.RangeActionsNotSupported
- throw new…
AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14).
Data as JSON: /api/errors/dc36f7ffc11cc8b8.
Report an issue: GitHub.
Appendix: source
Thrown at src/Microsoft.DotNet.Wpf/src/PresentationFramework/MS/Internal/Data/EnumerableCollectionView.cs:426
}
else
{ // insert
for (int i = args.NewItems.Count - 1; i >= 0; --i)
{
_snapshot.Insert(args.NewStartingIndex, args.NewItems[i]);
}
}
break;
case NotifyCollectionChangedAction.Remove:
if (args.OldStartingIndex < 0)
throw new InvalidOperationException(SR.RemovedItemNotFound);
for (int i = args.OldItems.Count - 1, index = args.OldStartingIndex + i; i >= 0; --i, --index)
{
if (!System.Windows.Controls.ItemsControl.EqualsEx(args.OldItems[i], _snapshot[index]))
// replace error message with a better one
throw new InvalidOperationException(SR.Format(SR.AddedItemNotAtIndex, index));
_snapshot.RemoveAt(index);
}
break;
case NotifyCollectionChangedAction.Replace:
for (int i = args.NewItems.Count - 1, index = args.NewStartingIndex + i; i >= 0; --i, --index)
{
if (!System.Windows.Controls.ItemsControl.EqualsEx(args.OldItems[i], _snapshot[index]))
// replace error message with a better one
throw new InvalidOperationException(SR.Format(SR.AddedItemNotAtIndex, index));
_snapshot[index] = args.NewItems[i];
}
break;
case NotifyCollectionChangedAction.Move:
if (args.NewStartingIndex < 0)
throw new InvalidOperationException(SR.CannotMoveToUnknownPosition);
View on GitHub (pinned to 81131a70a4)