dotnet/wpf · error · InvalidOperationException

SR.EnumeratorNotStarted

Error message

SR.EnumeratorNotStarted

What it means

HostedElements' enumerator exposes IEnumerator.Current before enumeration has begun. Per the IEnumerator contract, accessing Current before the first MoveNext() call throws InvalidOperationException with SR.EnumeratorNotStarted. The source shows Current only dereferences _currentPosition when it is non-null; otherwise it throws.

Solutions

  1. Call MoveNext() at least once and only read Current when it returns true.
  2. Use a foreach loop over the HostedElements collection instead of manual enumerator handling so the protocol is enforced.
  3. Guard reads of Current with a check that MoveNext has succeeded at least once.
  4. Reset the enumerator (or obtain a new one) if you need to iterate again after it finished.

Example fix

// before
var enumerator = hostedElements.GetEnumerator();
var first = enumerator.Current; // throws InvalidOperationException

// after
var enumerator = hostedElements.GetEnumerator();
if (enumerator.MoveNext())
{
    var first = enumerator.Current;
}
Defensive patterns

Strategy: validation

Validate before calling

// Track MoveNext success before reading Current
bool moved = enumerator.MoveNext();
if (!moved)
{
    return; // nothing to read; Current is not valid
}
var current = enumerator.Current;

Try / catch

try
{
    var current = enumerator.Current;
}
catch (InvalidOperationException)
{
    // enumerator not started or exhausted — call MoveNext first
}

Prevention

When it happens

Trigger: Reading the Current property of a HostedElements enumerator immediately after GetEnumerator() without calling MoveNext() first. Also occurs after a MoveNext() that returned false (enumeration finished), if code keeps reading Current.

Common situations: Hand-rolled foreach replacements (explicit MoveNext/Current loops) that read Current before the first MoveNext; copying enumerator state across iterations; code refactored from foreach to manual enumeration that reordered the calls.

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

Appendix: source

Thrown at src/Microsoft.DotNet.Wpf/src/PresentationFramework/MS/Internal/documents/HostedElements.cs:168

        }

        public IInputElement Current
        {
            get
            {
                // HostedElements must throw exception if Current property is incorrectly accessed
                if (_textSegments == null)
                {
                    // Collection was modified 
                    // IEnumerator.Current is documented to throw this exception
                    throw new InvalidOperationException(SR.EnumeratorCollectionDisposed);
                }

                if (_currentPosition == null)
                {
                    // Enumerator not started. Call MoveNext to see if we can move ahead
                    // IEnumerator.Current is documented to throw this exception
                    throw new InvalidOperationException(SR.EnumeratorNotStarted);
                }

                IInputElement currentElement = null;
                switch (_currentPosition.GetPointerContext(LogicalDirection.Forward))
                {
                    case TextPointerContext.ElementStart:
                        Debug.Assert(_currentPosition.GetAdjacentElementFromOuterPosition(LogicalDirection.Forward) is IInputElement);
                        currentElement = _currentPosition.GetAdjacentElementFromOuterPosition(LogicalDirection.Forward);
                        break;
                    case TextPointerContext.EmbeddedElement:
                        Debug.Assert(_currentPosition.GetAdjacentElement(LogicalDirection.Forward) is IInputElement);
                        currentElement = (IInputElement)_currentPosition.GetAdjacentElement(LogicalDirection.Forward);
                        break;
                    default:
                        // Throw exception because this function should only be called after MoveNext, and not 
                        // if MoveNext returns false
                        Debug.Fail("Invalid state in HostedElements.cs");
                        break;

View on GitHub (pinned to 81131a70a4)