dotnet/wpf · error · InvalidOperationException

SR.Enumerator_ReachedEnd

Error message

SR.Enumerator_ReachedEnd

What it means

The enumerator's Current property throws InvalidOperationException (SR.Enumerator_ReachedEnd) when accessed after enumeration has completed (_index == -2, i.e. MoveNext returned false or Reset-terminated state). Current cannot be read past the end of the collection.

Solutions

  1. Read Current only when MoveNext() returns true, and store the value locally inside the loop
  2. Track your own 'last element' variable instead of re-reading Current after the loop
  3. Use foreach which guarantees Current is never read past the end

Example fix

// before
while (e.MoveNext()) { }
var last = e.Current;
// after
object last = null;
while (e.MoveNext()) { last = e.Current; }
Defensive patterns

Strategy: validation

Validate before calling

// capture the value inside the loop instead of after it
object last = null;
while (enumerator.MoveNext()) { last = enumerator.Current; }

Try / catch

InvalidOperationException ex -> stop reading Current once MoveNext() returned false; keep a local copy of the last item

Prevention

When it happens

Trigger: Reading Current after MoveNext() returned false, or re-reading Current in code after a completed foreach (accessing a stored enumerator).

Common situations: Loop that reads Current after the terminating MoveNext; capturing enumerator.Current in a closure executed later; while-loop patterns that read before checking MoveNext's return on the final iteration.

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


AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14). Data as JSON: /api/errors/92da258f94e4f951. Report an issue: GitHub.

Appendix: source

Thrown at src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Generated/TextDecorationCollection.cs:845

            /// off the end of the list. However, the IEnumerable.Current
            /// contract requires that we throw exceptions
            /// </summary>
            public TextDecoration 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 TextDecoration _current;
            private TextDecorationCollection _list;
            private uint _version;
            private int _index;
            #endregion
        }
        #endregion

        #region Constructors

        //------------------------------------------------------

View on GitHub (pinned to 81131a70a4)