dotnet/wpf · error · InvalidOperationException
SR.Enumerator_CollectionChanged
Error message
SR.Enumerator_CollectionChanged
What it means
Thrown by the collection enumerator's MoveNext when the underlying GeneralTransformCollection was modified after the enumerator was created. The enumerator's version stamp no longer matches the collection's, so iteration is aborted with an InvalidOperationException.
Solutions
- Collect items to add/remove into a temporary list and apply them after the foreach completes
- Iterate over a snapshot (e.g. collection.ToArray()) when mutation may occur
- Use a for loop with index bounds checks if deliberate mutation-while-iterating is required
Example fix
// before
foreach (var t in collection) { if (bad(t)) collection.Remove(t); }
// after
var toRemove = collection.Where(bad).ToArray();
foreach (var t in toRemove) { collection.Remove(t); } Defensive patterns
Strategy: try-catch
Try / catch
bool done = false;
while (!done) {
try { foreach (var t in collection.ToArray()) { Process(t); } done = true; }
catch (InvalidOperationException) { /* retry with fresh snapshot */ }
} Prevention
- Never mutate a collection inside its own foreach loop
- Iterate over a snapshot (ToArray) when mutation can occur
- Synchronize cross-thread access or marshal mutations to the owning thread (Dispatcher)
When it happens
Trigger: Calling Add, Remove, Insert, Clear, or the indexer setter while a foreach loop is enumerating the collection — including modifications made from event handlers, animation callbacks, or another thread during enumeration.
Common situations: Enumerating a TransformCollection and adding transforms inside the loop, UI-driven handlers mutating the collection during enumeration, or cross-thread access without synchronization.
Related errors
- SR.Enumerator_CollectionChanged
- SR.Enumerator_CollectionChanged
- SR.Enumerator_CollectionChanged
- SR.Enumerator_CollectionChanged
- InvalidOperationException
AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14).
Data as JSON: /api/errors/9f198d6bd8763fa9.
Report an issue: GitHub.
Appendix: source
Thrown at src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/Generated/GeneralTransformCollection.cs:797
{
_list.ReadPreamble();
if (_version == _list._version)
{
if (_index > -2 && _index < _list._collection.Count - 1)
{
_current = _list._collection[++_index];
return true;
}
else
{
_index = -2; // -2 indicates "past the end"
return false;
}
}
else
{
throw new InvalidOperationException(SR.Enumerator_CollectionChanged);
}
}
/// <summary>
/// Sets the enumerator to its initial position, which is before the
/// first element in the collection.
/// </summary>
public void Reset()
{
_list.ReadPreamble();
if (_version == _list._version)
{
_index = -1;
}
else
{
throw new InvalidOperationException(SR.Enumerator_CollectionChanged);View on GitHub (pinned to 81131a70a4)