dotnet/wpf · error · InvalidOperationException

throw new…

Error message

throw new InvalidOperationException(SR.EnumeratorVersionChanged);

What it means

IndexedEnumerable's IEnumerator.Reset() requires the owning IndexedEnumerable to still reference a live enumerable (_enumerable != null). When the parent enumerable was replaced or cleared (e.g. the view re-created the IndexedEnumerable after a collection change), Reset() treats the enumerator as orphaned and throws InvalidOperationException with EnumeratorVersionChanged.

Solutions

  1. Discard the stale enumerator and request a new one via GetEnumerator() instead of calling Reset().
  2. Re-query the view/enumerable after any Refresh or rebind before resuming iteration.
  3. Restructure iteration into a method that creates a fresh enumerator on each pass.
  4. Catch InvalidOperationException and fall back to re-enumeration with a new enumerator.

Example fix

// before
enumerator.Reset(); // stale after refresh
// after
enumerator = indexedEnumerable.GetEnumerator(); // fresh enumerator
Defensive patterns

Strategy: try-catch

Try / catch

try { enumerator.Reset(); }
catch (InvalidOperationException) { enumerator = enumerable.GetEnumerator(); }

Prevention

When it happens

Trigger: Calling IEnumerator.Reset() (explicit interface implementation) on an enumerator obtained from an IndexedEnumerable after the source enumerable was detached — typically following a collection Refresh or rebind that invalidated the enumerator.

Common situations: Holding an IEnumerator across a CollectionView.Refresh() or ItemsSource change and calling Reset() to restart iteration; long-lived enumerators stored in helper classes while the view rebinds.

Related errors


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

Appendix: source

Thrown at src/Microsoft.DotNet.Wpf/src/PresentationFramework/MS/Internal/Data/IndexedEnumerable.cs:722

        //------------------------------------------------------
        //
        //  Private Types
        //
        //------------------------------------------------------
        private class FilteredEnumerator : IEnumerator, IDisposable
        {
            public FilteredEnumerator(IndexedEnumerable indexedEnumerable, IEnumerable enumerable, Predicate<object> filterCallback)
            {
                _enumerable = enumerable;
                _enumerator = _enumerable.GetEnumerator();
                _filterCallback = filterCallback;
                _indexedEnumerable = indexedEnumerable;
            }

            void IEnumerator.Reset()
            {
                if (_indexedEnumerable._enumerable == null)
                    throw new InvalidOperationException(SR.EnumeratorVersionChanged);

                Dispose();
                _enumerator = _enumerable.GetEnumerator();
            }

            bool IEnumerator.MoveNext()
            {
                bool returnValue;

                if (_indexedEnumerable._enumerable == null)
                    throw new InvalidOperationException(SR.EnumeratorVersionChanged);

                if (_filterCallback == null)
                {
                    returnValue = _enumerator.MoveNext();
                }
                else
                {

View on GitHub (pinned to 81131a70a4)