dotnet/wpf · error · InvalidOperationException
SR.Enumerator_ReachedEnd
Error message
SR.Enumerator_ReachedEnd
What it means
TransformCollection.Enumerator.Current throws InvalidOperationException with Enumerator_ReachedEnd when accessed after MoveNext() returned false (past the end, _index == -2). There is no current element once enumeration has completed.
Solutions
- Only read Current when MoveNext() returned true; capture the value inside the loop body.
- Cache the last valid Current item in a local variable before the loop ends if you need it afterwards.
- Use foreach to make out-of-range Current access impossible.
- Catch InvalidOperationException around Current access if legacy code cannot be restructured.
Example fix
// before
Transform last = null;
var e = transformCollection.GetEnumerator();
while (e.MoveNext()) { }
last = e.Current; // throws: past end
// after
Transform last = null;
foreach (Transform t in transformCollection)
{
last = t;
} Defensive patterns
Strategy: validation
Validate before calling
// Only read Current when MoveNext() returned true:
while (enumerator.MoveNext())
{
var current = enumerator.Current; // safe inside loop
} Type guard
static Transform LastOrDefault(TransformCollection c)
{
if (c == null || c.Count == 0) return null;
return c[c.Count - 1]; // index access instead of enumerator Current
} Try / catch
try
{
var cur = enumerator.Current;
}
catch (InvalidOperationException)
{
// enumeration already past end; use the last value captured inside the loop
} Prevention
- Capture Current into a local variable inside the loop; never read it after the loop.
- Use the collection indexer (collection[Count-1]) instead of an exhausted enumerator to get the last item.
- Prefer foreach or LINQ over manual enumerator lifecycle.
When it happens
Trigger: Reading Current after MoveNext() returned false, or accessing Current again after a completed foreach; any code that keeps the enumerator alive past the last element and dereferences Current.
Common situations: Loops that read Current after the loop 'just in case'; storing the enumerator and reading Current later; do/while loops that check Current before MoveNext's return value.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- SR.Enumerator_NotStarted
- 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/15b3a96792ae1315.
Report an issue: GitHub.
Appendix: source
Thrown at src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/Generated/TransformCollection.cs:889
/// off the end of the list. However, the IEnumerable.Current
/// contract requires that we throw exceptions
/// </summary>
public Transform Current
{
get
{
if (_index > -1)
{
return _current;
}
else if (_index == -1)
{
throw new InvalidOperationException(SR.Enumerator_NotStarted);
}
else
{
Debug.Assert(_index == -2, "expected -2, got " + _index + "\n");
throw new InvalidOperationException(SR.Enumerator_ReachedEnd);
}
}
}
#endregion
#region Data
private Transform _current;
private TransformCollection _list;
private uint _version;
private int _index;
#endregion
}
#endregion
#region Constructors
//------------------------------------------------------View on GitHub (pinned to 81131a70a4)