dotnet/wpf · error · InvalidOperationException

SR.Format(SR.InconsistentBindingList, InternalList…

Error message

SR.Format(SR.InconsistentBindingList, InternalList, args.ListChangedType)

What it means

During an ItemAdded ListChanged notification, the view keeps a cached shadow list (_cachedList) in sync with the source InternalList. If after inserting the new item the two lists' counts differ, the binding list is inconsistent with its own change notifications and the view throws InvalidOperationException with SR.InconsistentBindingList.

Solutions

  1. Fix the IBindingList to add the item to its backing store before raising ListChanged(ItemAdded).
  2. Ensure each add raises exactly one ItemAdded notification.
  3. Catch the InvalidOperationException and call Refresh() on the view to resynchronize the cache.
  4. Replace the custom list with a standard BindingList<T>, which maintains the notification contract correctly.

Example fix

// before
// custom list raises ListChanged(ItemAdded) before inserting
collection.Add(item); // item inserted AFTER notification

// after
// insert first, then notify
_innerList.Insert(index, item);
onListChanged(new ListChangedEventArgs(ListChangedType.ItemAdded, index));
Defensive patterns

Strategy: try-catch

Validate before calling

// after handling an add on the source list, verify it is consistent
Debug.Assert(internalList.Count == expectedCount, "list changed without consistent notification");

Try / catch

try { collection.Add(item); }
catch (InvalidOperationException ex) when (ex.Message.Contains("binding list")) { view.Refresh(); }

Prevention

When it happens

Trigger: The source IBindingList raises ListChanged(ItemAdded, index) but its internal list does not actually contain the item at that index afterward, so InternalList.Count != _cachedList.Count after the view inserts the item into its cache.

Common situations: Custom IBindingList implementations that fire ItemAdded before or without actually adding the item; double-firing Add notifications; race conditions where the list is modified again before the view processes the event.

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/180b25d87dd62082. Report an issue: GitHub.

Appendix: source

Thrown at src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Data/BindingListCollectionView.cs:1917

                // they arise from a commit that we initiated.  There's
                // no way to detect them from the event args;  we do it the same
                // way WinForms.DataGridView does - by comparing counts.
                if (InternalList.Count == _cachedList.Count)
                {
                    if (IsAddingNew && index == _newItemIndex)
                    {
                        Debug.Assert(_newItem == InternalList[index], "unexpected item while committing AddNew");
                        forwardedArgs = ProcessCommitNew(index + delta, index + delta);
                    }
                }
                else
                {
                    // normal ItemAdded event
                    item = InternalList[index];
                    forwardedArgs = new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item, index + delta);
                    _cachedList.Insert(index, item);
                    if (InternalList.Count != _cachedList.Count)
                        throw new InvalidOperationException(SR.Format(SR.InconsistentBindingList, InternalList, args.ListChangedType));
                    if (index <= _newItemIndex)
                    {
                        ++ _newItemIndex;
                    }
                }
                break;

            case ListChangedType.ItemDeleted:
                item = _cachedList[index];
                _cachedList.RemoveAt(index);
                if (InternalList.Count != _cachedList.Count)
                    throw new InvalidOperationException(SR.Format(SR.InconsistentBindingList, InternalList, args.ListChangedType));
                if (index < _newItemIndex)
                {
                    -- _newItemIndex;
                }

                // implicitly cancel AddNew and/or EditItem transactions if the relevant item is removed

View on GitHub (pinned to 81131a70a4)