dotnet/wpf · error · InvalidOperationException

SR.Enumerator_ReachedEnd

Error message

SR.Enumerator_ReachedEnd

What it means

GeneralTransformCollection.Enumerator.Current throws this InvalidOperationException when the enumerator has already walked past the end of the collection (internal _index == -2, set when MoveNext() returned false). Per the IEnumerator.Current contract, reading Current after exhaustion must throw rather than return the last item or default.

Solutions

  1. Read Current only inside the loop guarded by a true result from MoveNext().
  2. Keep a local variable holding the last valid item instead of re-reading Current after iteration finishes.
  3. Replace manual enumerator code with foreach, which never reads Current after the end.
  4. If a re-read is needed, call Reset() then MoveNext() to reposition before accessing Current.

Example fix

// before
while (e.MoveNext()) { }
var last = e.Current; // throws: past the end

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

Strategy: validation

Validate before calling

// keep the last valid item while iterating
T last = default;
while (enumerator.MoveNext()) { last = enumerator.Current; }

Type guard

static bool TryGetCurrent<T>(this IEnumerator<T> e, out T current) { bool ok = e.MoveNext(); current = ok ? e.Current : default; return ok; }

Try / catch

try { var v = enumerator.Current; }
catch (InvalidOperationException) { /* enumerator exhausted: capture items during iteration instead */ }

Prevention

When it happens

Trigger: Accessing Current after MoveNext() has returned false (collection fully consumed), then calling MoveNext() again (which keeps _index at -2) and reading Current, or reading Current repeatedly after the loop ended.

Common situations: Manual while(e.MoveNext()) loops that read e.Current after the loop body; code that stores the enumerator and reads Current later assuming it keeps the last value; loops with a trailing Current read outside the MoveNext()==true check.

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/f0bf6c679165f381. Report an issue: GitHub.

Appendix: source

Thrown at src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/Generated/GeneralTransformCollection.cs:854

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

        #region Constructors

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

View on GitHub (pinned to 81131a70a4)