{"record":{"id":"180b25d87dd62082","repo":"dotnet/wpf","slug":"sr-format-sr-inconsistentbindinglist-internallist-args","errorCode":null,"errorMessage":"SR.Format(SR.InconsistentBindingList, InternalList, args.ListChangedType)","messagePattern":"SR\\.Format\\(SR\\.InconsistentBindingList, InternalList, args\\.ListChangedType\\)","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Data/BindingListCollectionView.cs","lineNumber":1917,"sourceCode":"                // they arise from a commit that we initiated.  There's\n                // no way to detect them from the event args;  we do it the same\n                // way WinForms.DataGridView does - by comparing counts.\n                if (InternalList.Count == _cachedList.Count)\n                {\n                    if (IsAddingNew && index == _newItemIndex)\n                    {\n                        Debug.Assert(_newItem == InternalList[index], \"unexpected item while committing AddNew\");\n                        forwardedArgs = ProcessCommitNew(index + delta, index + delta);\n                    }\n                }\n                else\n                {\n                    // normal ItemAdded event\n                    item = InternalList[index];\n                    forwardedArgs = new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item, index + delta);\n                    _cachedList.Insert(index, item);\n                    if (InternalList.Count != _cachedList.Count)\n                        throw new InvalidOperationException(SR.Format(SR.InconsistentBindingList, InternalList, args.ListChangedType));\n                    if (index <= _newItemIndex)\n                    {\n                        ++ _newItemIndex;\n                    }\n                }\n                break;\n\n            case ListChangedType.ItemDeleted:\n                item = _cachedList[index];\n                _cachedList.RemoveAt(index);\n                if (InternalList.Count != _cachedList.Count)\n                    throw new InvalidOperationException(SR.Format(SR.InconsistentBindingList, InternalList, args.ListChangedType));\n                if (index < _newItemIndex)\n                {\n                    -- _newItemIndex;\n                }\n\n                // implicitly cancel AddNew and/or EditItem transactions if the relevant item is removed","sourceCodeStart":1899,"sourceCodeEnd":1935,"githubUrl":"https://github.com/dotnet/wpf/blob/81131a70a4c573cd62748a5c36908fc4d662daa9/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Data/BindingListCollectionView.cs#L1899-L1935","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\n// custom list raises ListChanged(ItemAdded) before inserting\ncollection.Add(item); // item inserted AFTER notification\n\n// after\n// insert first, then notify\n_innerList.Insert(index, item);\nonListChanged(new ListChangedEventArgs(ListChangedType.ItemAdded, index));","handlingStrategy":"try-catch","validationCode":"// after handling an add on the source list, verify it is consistent\nDebug.Assert(internalList.Count == expectedCount, \"list changed without consistent notification\");","typeGuard":null,"tryCatchPattern":"try { collection.Add(item); }\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"binding list\")) { view.Refresh(); }","preventionTips":["Insert the item before raising ItemAdded","Raise exactly one notification per mutation","Unit-test custom IBindingList change notifications against CollectionView"],"tags":["wpf","data-binding","inconsistent-binding-list","internal-invariant"],"backgroundTag":"internal-invariant-violation","analyzedSha":"81131a70a4c573cd62748a5c36908fc4d662daa9","analyzedAt":"2026-09-14T10:12:48.479Z","contentChangedAt":"2026-09-14T10:12:48.479Z","schemaVersion":2},"datasetVersion":"2026-09-21T21:30:21.729Z"}