dotnet/wpf · critical · InvalidOperationException
SR.Generator_Inconsistent
Error message
SR.Generator_Inconsistent
What it means
ItemContainerGenerator periodically validates that its internal item map is consistent with the Items collection (VerifyItemMapAndSource). When a mismatch is detected it builds a detailed diagnostic string, wraps it in an inner Exception, and throws InvalidOperationException SR.Generator_Inconsistent to report a broken generator state.
Solutions
- Fix the source collection so its CollectionChanged notifications exactly match its contents (each Add/Remove reflects real items).
- Implement INotifyCollectionChanged correctly on custom collections, or wrap with ObservableCollection.
- Never mutate the Items collection from multiple threads or re-entrantly while CollectionChanged handlers run.
Example fix
// before
class BuggyCollection : List<object>, INotifyCollectionChanged { /* raises events inconsistently */ }
// after
class FixedCollection : ObservableCollection<object> { } // notifications always match contents Defensive patterns
Strategy: try-catch
Try / catch
try { /* bind / refresh ItemsSource */ }
catch (InvalidOperationException ex) when (ex.InnerException != null && ex.Message.Contains("inconsistent"))
{
// inspect ex.InnerException for the detailed map dump, then force refresh
itemsControl.Items.Refresh();
} Prevention
- Implement INotifyCollectionChanged correctly on custom collections; test with the WPF generator.
- Mutate collections only on the UI thread.
- Never raise CollectionChanged handlers that mutate the same collection re-entrantly.
When it happens
Trigger: The Items collection was mutated in ways the generator could not track — e.g. raising CollectionChanged events that do not match the actual collection contents, direct mutation of ItemsInternal without notifications, or custom IList implementations raising inconsistent Add/Remove events.
Common situations: Custom collection classes with buggy INotifyCollectionChanged implementations; modifying ItemsSource collection from background threads; re-entrancy during collection change notifications.
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
- SR.CannotFindRemovedItem
- SR.Format(SR.CollectionAddEventMissingItem, item)
- SR.Freezable_UnexpectedChange
- SR.RangeActionsNotSupported
- InvalidOperationException
AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14).
Data as JSON: /api/errors/cf21c32010065343.
Report an issue: GitHub.
Appendix: source
Thrown at src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Controls/ItemContainerGenerator.cs:1101
sb.AppendLine();
sb.AppendLine(SR.Generator_Readme5); // The most common causes...
sb.AppendLine();
sb.Append (SR.Generator_Readme6); sb.Append(" "); // Stack trace describes detection...
sb.Append (SR.Format(SR.Generator_Readme7, // To get better detection...
"PresentationTraceSources.TraceLevel", "High"));
sb.Append (" ");
sb.AppendLine(SR.Format(SR.Generator_Readme8, // One way to do this ...
"System.Diagnostics.PresentationTraceSources.SetTraceLevel(myItemsControl.ItemContainerGenerator, System.Diagnostics.PresentationTraceLevel.High)"));
sb.AppendLine(SR.Generator_Readme9); // This slows down the app.
// use an inner exception to hold the details. There's a lot of
// information, but it's only interesting to a developer.
Exception exception = new Exception(sb.ToString());
// throw the exception
throw new InvalidOperationException(SR.Generator_Inconsistent, exception);
}
}
private void FormatCollectionChangedSource(int level, object source, bool? isLikely, List<string> sources)
{
Type sourceType = source.GetType();
if (!isLikely.HasValue)
{
// if the type doesn't come from WPF or DevDiv (e.g. ObservableCollection<T>),
// mark it as "more likely to be at fault". I'm not saying we're always right,
// just that 3rd parties are more likely to be wrong than we are.
isLikely = true;
const string PublicKeyToken = "PublicKeyToken=";
string aqn = sourceType.AssemblyQualifiedName;
int index = aqn.LastIndexOf(PublicKeyToken);
if (index >= 0)View on GitHub (pinned to 81131a70a4)