dotnet/wpf · error · InvalidOperationException
SR.EnumeratorCollectionDisposed
Error message
SR.EnumeratorCollectionDisposed
What it means
The HostedElements enumerator's Current getter throws InvalidOperationException (SR.EnumeratorCollectionDisposed) when the enumerator has been disposed/reset (_textSegments == null). Per the IEnumerator contract, accessing Current after the collection state is gone is an error; the comment notes this also covers 'collection was modified'.
Solutions
- Do not read Current after Reset or after the enumerator finished; call MoveNext first and check its result before accessing Current.
- Acquire a new enumerator from HostedElements when you need to iterate again.
- Avoid caching enumerators of FlowDocument content across content edits.
Example fix
// before
enumerator.Reset();
var el = enumerator.Current; // throws
// after
enumerator = hostedElements.GetEnumerator();
if (enumerator.MoveNext()) { var el = enumerator.Current; } Defensive patterns
Strategy: validation
Validate before calling
if (enumerator.MoveNext())
{
var current = enumerator.Current;
}
// Only read Current after a successful MoveNext; never after Reset. Type guard
static bool TryReadCurrent(IEnumerator e, out object value)
{ value = null; try { value = e.Current; return true; } catch (InvalidOperationException) { return false; } } Try / catch
try { var el = enumerator.Current; }
catch (InvalidOperationException) { enumerator = hostedElements.GetEnumerator(); } Prevention
- Read Current only after a true MoveNext result
- Re-create enumerators after Reset or content edits
- Do not cache HostedElements enumerators across document changes
When it happens
Trigger: Reading Current after calling Reset (which effectively disposes the enumerator's state) or otherwise after the enumerator's internal text-segment list was cleared — including from a finally/deferred block or a cached enumerator kept after iteration ended.
Common situations: Storing the enumerator long-term and reading Current later; generic iteration helpers that touch Current after Reset or after the document content changed, invalidating the 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
- SR.Enumerator_NotStarted
- SR.Enumerator_NotStarted
- SR.Enumerator_NotStarted
- SR.Enumerator_NotStarted
- SR.Enumerator_ReachedEnd
AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14).
Data as JSON: /api/errors/c3608a53b8fa72d5.
Report an issue: GitHub.
Appendix: source
Thrown at src/Microsoft.DotNet.Wpf/src/PresentationFramework/MS/Internal/documents/HostedElements.cs:161
{
get { return this.Current; }
}
void IEnumerator.Reset()
{
throw new NotImplementedException();
}
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);View on GitHub (pinned to 81131a70a4)