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

  1. Do not read Current after Reset or after the enumerator finished; call MoveNext first and check its result before accessing Current.
  2. Acquire a new enumerator from HostedElements when you need to iterate again.
  3. 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

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


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)