dotnet/wpf · error · InvalidOperationException

SR.Enumerator_ReachedEnd

Error message

SR.Enumerator_ReachedEnd

What it means

This InvalidOperationException is thrown by a CollectionHelper-generated enumerator when Current is accessed after iteration has completed: MoveNext() returned false (internal _index == -2, meaning the enumerator is past the last element). It enforces the IEnumerator contract that Current is undefined once the enumeration is finished.

Solutions

  1. Capture the last value inside the loop before MoveNext() returns false.
  2. Call Reset() (or obtain a fresh enumerator) to iterate again from the start.
  3. Restructure as foreach so Current is only read at valid positions.

Example fix

// before
foreach (var x in collection) { }
var last = e.Current; // throws: reached end
// after
T last = default;
foreach (var x in collection) { last = x; }
Defensive patterns

Strategy: try-catch

Validate before calling

while (e.MoveNext())
{
    last = e.Current; // save inside the loop, never after
}

Type guard

static bool TryLast<T>(IEnumerable<T> seq, out T value) { value = default; using var e = seq.GetEnumerator(); if (!e.MoveNext()) return false; value = e.Current; while (e.MoveNext()) value = e.Current; return true; }

Try / catch

try { var item = enumerator.Current; }
catch (InvalidOperationException ex) when (ex.Message.Contains("ReachedEnd") || ex.Message.Contains("end")) { /* enumeration finished; re-enumerate if needed */ }

Prevention

When it happens

Trigger: Accessing Current after MoveNext() has returned false, or continuing to read Current after a foreach loop over the collection has finished.

Common situations: Keeping a reference to the enumerator and reading Current after the loop; trying to get the 'last' element after the loop ended instead of saving it inside the loop; reusing an exhausted enumerator.

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

Appendix: source

Thrown at src/Microsoft.DotNet.Wpf/src/WpfGfx/codegen/mcg/helpers/CollectionHelper.cs:773

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

        public static string WriteCollectionMethods(McgResource resource)

View on GitHub (pinned to 81131a70a4)