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
- Fix the IBindingList to add the item to its backing store before raising ListChanged(ItemAdded).
- Ensure each add raises exactly one ItemAdded notification.
- Catch the InvalidOperationException and call Refresh() on the view to resynchronize the cache.
- 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
- Insert the item before raising ItemAdded
- Raise exactly one notification per mutation
- Unit-test custom IBindingList change notifications against CollectionView
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
- ArgumentNullException(nameof(value))
- (no message) NotSupportedException
- NotImplementedException (ConvertBack not supported)
- NotImplementedException (ConvertBack not supported)
- NotSupportedException (ConvertBack not supported)
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 removedView on GitHub (pinned to 81131a70a4)