dotnet/wpf · error · InvalidOperationException
SR.Enumerator_ReachedEnd
Error message
SR.Enumerator_ReachedEnd
What it means
FreezableCollection<T>.Enumerator.Current throws InvalidOperationException(SR.Enumerator_ReachedEnd) when accessed after enumeration has completed (_index == -2, i.e. MoveNext returned false and iteration went past the last element). Once exhausted, the enumerator has no current element.
Solutions
- Only read Current when MoveNext() returned true; capture the last item inside the loop before it ends.
- Remember the last valid item in a local during iteration if you need it after the loop.
- Create a fresh enumerator to iterate again instead of reading Current from the exhausted one.
Example fix
// before
while (e.MoveNext()) { }
var last = e.Current; // throws
// after
T last = default;
while (e.MoveNext()) { last = e.Current; } Defensive patterns
Strategy: validation
Validate before calling
if (!e.MoveNext()) return; // empty or exhausted: do not read Current var item = e.Current;
Type guard
bool TryPeekAfterMoveNext<T>(IEnumerator<T> e, out T value) { if (e.MoveNext()) { value = e.Current; return true; } value = default; return false; } Try / catch
try { var cur = e.Current; }
catch (InvalidOperationException) { /* enumeration already finished */ } Prevention
- Read Current only inside a successful MoveNext branch
- Track the last item in a local if needed after the loop
- Re-enumerate instead of reusing an exhausted enumerator
When it happens
Trigger: Reading Current after MoveNext() returned false — e.g. a do/while loop that reads Current after the terminating MoveNext, or accessing Current after a fully consumed foreach using the same enumerator object.
Common situations: Loops structured as 'while(true) { advanced = MoveNext(); var item = Current; ... }' where Current is read even when advanced is false, reusing an exhausted enumerator to 'get the last item'.
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_NotStarted
- SR.Enumerator_ReachedEnd
- SR.Enumerator_NotStarted
- SR.Enumerator_NotStarted
AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14).
Data as JSON: /api/errors/40cd3356fe6b3a92.
Report an issue: GitHub.
Appendix: source
Thrown at src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/FreezableCollection.cs:1079
/// off the end of the list. However, the IEnumerable.Current
/// contract requires that we throw exceptions
/// </summary>
public T 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 T _current;
private FreezableCollection<T> _list;
private uint _version;
private int _index;
#endregion
}
private class SimpleMonitor : IDisposable
{
public void Enter()
{View on GitHub (pinned to 81131a70a4)