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

  1. Only read Current when MoveNext() returned true; capture the value inside the loop body.
  2. Cache the last valid Current item in a local variable before the loop ends if you need it afterwards.
  3. Use foreach to make out-of-range Current access impossible.
  4. 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

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


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)