dotnet/wpf · critical · InvalidOperationException

SR.Format(SR.CollectionAddEventMissingItem, item)

Error message

SR.Format(SR.CollectionAddEventMissingItem, item)

What it means

When handling a CollectionChanged Add event, the generator must determine the index of the added item. If the event's NewStartingIndex was not supplied (index < 0), it falls back to ItemsInternal.IndexOf(item); if the item is not found in the Items collection, it throws InvalidOperationException (CollectionAddEventMissingItem), because the add event references an item the collection does not contain.

Solutions

  1. Always supply a valid NewStartingIndex when raising Add events, or ensure the item is already inserted before the event fires.
  2. Fix the custom collection so events reflect the post-change state (item present at reported index).
  3. Use ObservableCollection or a battle-tested collection wrapper instead of hand-rolled INotifyCollectionChanged.

Example fix

// before
OnCollectionChanged(new NotifyCollectionChangedEventArgs(Add, item, -1)); // item not yet inserted

// after
items.Insert(index, item);
OnCollectionChanged(new NotifyCollectionChangedEventArgs(Add, item, index));
Defensive patterns

Strategy: validation

Validate before calling

// In your INotifyCollectionChanged source, before raising Add:
if (newStartingIndex < 0 && !items.Contains(item))
    throw new InvalidOperationException("Add event must reference an item present in the collection");

Try / catch

try { /* process add event */ }
catch (InvalidOperationException ex) when (ex.Message.Contains("add event"))
{
    itemsControl.Items.Refresh();
}

Prevention

When it happens

Trigger: A source collection raises NotifyCollectionChangedAction.Add with NewStartingIndex = -1 and an item that is not actually present in the Items collection — typically from a custom INotifyCollectionChanged implementation raising stale or mismatched events.

Common situations: Custom collections firing Add events for items before actually inserting them; event replay/caching layers that duplicate or reorder notifications; GroupStyle scenarios where events come from the wrong collection.

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/5ff6ce16381a1e1f. Report an issue: GitHub.

Appendix: source

Thrown at src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Controls/ItemContainerGenerator.cs:2375

            else
            {
                OnRefresh();
            }
        }

        private void ValidateAndCorrectIndex(object item, ref int index)
        {
            if (index >= 0)
            {
                // this check is expensive - Items[index] potentially iterates through
                // the collection.  So trust the sender to tell us the truth in retail bits.
                Debug.Assert(ItemsControl.EqualsEx(item, ItemsInternal[index]), "Event contains the wrong index");
            }
            else
            {
                index = ItemsInternal.IndexOf(item);
                if (index < 0)
                    throw new InvalidOperationException(SR.Format(SR.CollectionAddEventMissingItem, item));
            }
        }

        /// <summary>
        /// Forward a CollectionChanged event
        /// </summary>
        // Called  when items collection changes.
        private void OnCollectionChanged(object sender, NotifyCollectionChangedEventArgs args)
        {
            if (sender != ItemsInternal && args.Action != NotifyCollectionChangedAction.Reset)
                return;     // ignore events (except Reset) from ItemsCollection when we're listening to group's items.

            switch (args.Action)
            {
                case NotifyCollectionChangedAction.Add:
                    if (args.NewItems.Count != 1)
                        throw new NotSupportedException(SR.RangeActionsNotSupported);
                    OnItemAdded(args.NewItems[0], args.NewStartingIndex);

View on GitHub (pinned to 81131a70a4)