dotnet/wpf · error · InvalidOperationException
SR.Enumerator_ReachedEnd
Error message
SR.Enumerator_ReachedEnd
What it means
Model3DCollection's enumerator Current property throws InvalidOperationException(SR.Enumerator_ReachedEnd) when Current is accessed after MoveNext has returned false (i.e. the enumerator position is past the end, _index == -2). The WPF generated collection enumerators enforce strict access ordering: Current is only valid while positioned on an element.
Solutions
- Read Current only inside the loop, immediately after MoveNext() returns true
- Call Reset() before reusing an enumerator, or simply create a new one via GetEnumerator()
- Prefer a foreach loop over manual MoveNext/Current code so the compiler enforces correct usage
Example fix
// before
var e = collection.GetEnumerator();
while (e.MoveNext()) { }
Console.WriteLine(e.Current); // throws
// after
foreach (Model3D m in collection)
Console.WriteLine(m); Defensive patterns
Strategy: try-catch
Validate before calling
bool canReadCurrent = enumeratorHasStarted && !enumeratorFinished; // track MoveNext results yourself
Type guard
bool CanReadCurrent(System.Collections.IEnumerator e, bool lastMoveNextResult) => lastMoveNextResult;
Try / catch
try { var cur = e.Current; }
catch (InvalidOperationException) { /* enumerator past end; re-enumerate */ e.Reset(); } Prevention
- Use foreach instead of manual MoveNext/Current loops
- Never read Current outside an active loop iteration
- Create a fresh enumerator for each pass instead of reusing
When it happens
Trigger: Accessing the Current property after a foreach loop has completed, or after calling MoveNext() until it returns false and then reading Current without calling Reset().
Common situations: Reusing a single enumerator object across multiple passes; storing the enumerator and reading Current after loop exit; hand-rolled iterator loops that forget to Reset() before reuse.
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_ReachedEnd
- Microsoft.Windows.Controls.SR.Format(Microsoft.Windows.Contr…
- Microsoft.Windows.Controls.SR.Format(Microsoft.Windows.Contr…
- Microsoft.Windows.Controls.SR.Ribbon_ContextualTabHeadersSou…
AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14).
Data as JSON: /api/errors/08198772d8b528f2.
Report an issue: GitHub.
Appendix: source
Thrown at src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media3D/Generated/Model3DCollection.cs:887
/// off the end of the list. However, the IEnumerable.Current
/// contract requires that we throw exceptions
/// </summary>
public Model3D 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 Model3D _current;
private Model3DCollection _list;
private uint _version;
private int _index;
#endregion
}
#endregion
#region Constructors
//------------------------------------------------------View on GitHub (pinned to 81131a70a4)