dotnet/wpf · error · InvalidOperationException

SR.Enumerator_NotStarted

Error message

SR.Enumerator_NotStarted

What it means

FreezableCollection<T>.Enumerator.Current throws InvalidOperationException(SR.Enumerator_NotStarted) when accessed before the first MoveNext call (_index == -1). There is no current element yet, so reading Current is undefined and rejected.

Solutions

  1. Call MoveNext() at least once and check it returned true before reading Current.
  2. Prefer foreach, which guarantees Current is only read after a successful MoveNext.
  3. Initialize/prime the enumerator before exposing it to code that reads Current.

Example fix

// before
var e = collection.GetEnumerator();
var first = e.Current; // throws
// after
var e = collection.GetEnumerator();
if (e.MoveNext()) { var first = e.Current; }
Defensive patterns

Strategy: validation

Validate before calling

if (!started) throw new InvalidOperationException("Call MoveNext() before reading Current.");

Type guard

bool TryGetFirst<T>(IEnumerator<T> e, out T value) { if (e.MoveNext()) { value = e.Current; return true; } value = default; return false; }

Try / catch

try { var cur = e.Current; }
catch (InvalidOperationException) { /* enumerator not started; call MoveNext first */ }

Prevention

When it happens

Trigger: Reading enumerator.Current (or using foreach's variable) before calling MoveNext, e.g. accessing Current immediately after GetEnumerator() or accessing the loop variable before the first iteration in hand-rolled loops.

Common situations: Hand-rolled enumeration code that reads Current before advancing, refactored foreach loops where an early 'peek' at Current was added, storing the enumerator and reading Current later before starting.

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

Appendix: source

Thrown at src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/FreezableCollection.cs:1074

            /// <summary>
            /// Current element
            ///
            /// The behavior of IEnumerable&lt;T>.Current is undefined
            /// before the first MoveNext and after we have walked
            /// off the end of the list. However, the IEnumerable.Current
            /// contract requires that we throw exceptions
            /// </summary>
            public T 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 T _current;
            private FreezableCollection<T> _list;
            private uint _version;
            private int _index;
            #endregion
        }

View on GitHub (pinned to 81131a70a4)