dotnet/wpf · error · InvalidOperationException

SR.EnumeratorInvalidOperation

Error message

SR.EnumeratorInvalidOperation

What it means

ModelTreeEnumerator's IEnumerator.Current getter throws InvalidOperationException('EnumeratorInvalidOperation') when Current is accessed before MoveNext() has positioned the enumerator at the first element. This is part of the documented IEnumerator.Current contract: Current is invalid before begin and after end.

Solutions

  1. Call MoveNext() (and check it returned true) before reading Current.
  2. Reset() the enumerator (or get a fresh one via GetEnumerator()) after it is exhausted.
  3. Replace manual enumeration with foreach or LINQ, which honor the contract.
  4. Check that content was not cleared, which can leave an enumerator positioned beyond end.

Example fix

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

Strategy: try-catch

Validate before calling

bool canReadCurrent = enumerator.MoveNext(); // check returned true before reading Current

Try / catch

try { var current = enumerator.Current; }
catch (InvalidOperationException) { /* call MoveNext/Reset first */ }

Prevention

When it happens

Trigger: Accessing the enumerator's Current property immediately after GetEnumerator() without calling MoveNext() first, or after MoveNext() returned false and Reset() was not called.

Common situations: Hand-written foreach replacements, enumerator passed to code that reads Current optimistically, custom LINQ-like helpers that peek at Current, or iterating model content (ItemsControl items / UIElementCollection wrappers) with a stale enumerator after the collection was emptied.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


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

Appendix: source

Thrown at src/Microsoft.DotNet.Wpf/src/PresentationFramework/MS/Internal/Controls/ModelTreeEnumerator.cs:77

                _index = value;
            }
        }

        protected virtual object Current
        {
            get
            {
                // Don't VerifyUnchanged(); According to MSDN:
                //     If the collection is modified between MoveNext and Current,
                //     Current will return the element that it is set to, even if
                //     the enumerator is already invalidated.

                if (_index == 0)
                {
                    return _content;
                }
                // Exception is part of the IEnumerator.Current contract when moving beyond begin/end
                throw new InvalidOperationException(SR.EnumeratorInvalidOperation);
            }
        }

        protected virtual bool MoveNext()
        {
            if (_index < 1)
            {
                // Singular content, can move next to 0 and that's it.
                _index++;

                if (_index == 0)
                {
                    // don't call VerifyUnchanged if we're returning false anyway.
                    // This permits users to change the Content after enumerating
                    // the content (e.g. in the invalidation callback of an inherited
                    // property).  See bug 955389.

                    VerifyUnchanged();

View on GitHub (pinned to 81131a70a4)