dotnet/wpf · error · InvalidOperationException
SR.Enumerator_CollectionChanged
Error message
SR.Enumerator_CollectionChanged
What it means
The Transform3DCollection enumerator's MoveNext throws InvalidOperationException (SR.Enumerator_CollectionChanged) when the collection's version stamp no longer matches the version captured when the enumerator was created. WPF collections invalidate enumerators on any add/remove to prevent undefined iteration.
Solutions
- Materialize the items first (foreach over collection.ToArray() or ToList()) before mutating.
- Collect items to remove in a separate list, then remove them after the loop.
- Synchronize access across threads (freeze the collection or dispatch mutations to one thread).
Example fix
// before
foreach (var t in collection)
if (ShouldRemove(t)) collection.Remove(t);
// after
foreach (var t in collection.ToArray())
if (ShouldRemove(t)) collection.Remove(t); Defensive patterns
Strategy: try-catch
Validate before calling
var snapshot = collection.ToArray();
foreach (var t in snapshot) { /* safe to mutate collection */ } Try / catch
try { foreach (var t in collection) { /* ... */ } } catch (InvalidOperationException) { /* collection changed during iteration; restart with snapshot */ } Prevention
- Never Add/Remove inside foreach over the live collection
- Iterate over ToArray()/ToList() when mutating
- Keep all mutations of Freezable collections on a single (UI) thread
- Freeze collections that should be immutable
When it happens
Trigger: Calling MoveNext after an element was added, removed, or replaced (indexer set) on the same collection during iteration.
Common situations: Removing items inside a foreach loop; a background thread mutating the collection while the UI thread iterates; building a filtered list by calling Remove while enumerating.
Related errors
- InvalidOperationException
- SR.Enumerator_CollectionChanged
- SR.Enumerator_CollectionChanged
- SR.Enumerator_CollectionChanged
- SR.Enumerator_CollectionChanged
AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14).
Data as JSON: /api/errors/f6c0cf146c040f94.
Report an issue: GitHub.
Appendix: source
Thrown at src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media3D/Generated/Transform3DCollection.cs:830
{
_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)