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
- Call MoveNext() at least once and only read Current when it returns true.
- Use a foreach loop over the HostedElements collection instead of manual enumerator handling so the protocol is enforced.
- Guard reads of Current with a check that MoveNext has succeeded at least once.
- 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
- Prefer foreach over manual MoveNext/Current handling.
- Only read Current when MoveNext() returned true.
- Never cache Current across enumerator reset or exhaustion.
- Re-create the enumerator instead of resetting when re-iterating.
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
- SR.Enumerator_CollectionChanged
- SR.Enumerator_CollectionChanged
- SR.Enumerator_CollectionChanged
- SR.Enumerator_CollectionChanged
- SR.Enumerator_CollectionChanged
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)