dotnet/wpf · error · InvalidOperationException

SR.Timing_EnumeratorInvalidated

Error message

SR.Timing_EnumeratorInvalidated

What it means

Thrown by the ClockEnumerator's MoveNext when the clock tree owned by the collection has been invalidated during enumeration (the owner is a ClockGroup whose InternalChildren list is no longer null/valid). WPF invalidates the clock tree when its timing structure changes, so any enumerator outstanding from GetEnumerator becomes invalid. This mirrors the standard 'collection modified during enumeration' contract.

Solutions

  1. Snapshot the clocks into a list (e.g. clockGroup.Children.ToList()) before iterating so enumeration does not depend on live internal state
  2. Re-fetch a fresh enumerator after any change to the clock/storyboard tree instead of reusing the old one
  3. Perform all clock-tree mutations and enumerations on the same thread and outside of active enumeration
  4. Wrap iteration in try/catch for InvalidOperationException and restart enumeration with fresh state

Example fix

// before
foreach (Clock clock in clockGroup)
{
    clock.ClockState = ...; // may mutate children
}
// after
var snapshot = clockGroup.Children.ToList();
foreach (Clock clock in snapshot)
{
    ...
}
Defensive patterns

Strategy: try-catch

Validate before calling

var snapshot = clockGroup.Children != null ? clockGroup.Children.ToList() : new List<Clock>();

Type guard

bool canEnumerate(ClockGroup g) => g != null && g.InternalChildren == null;

Try / catch

try
{
    foreach (Clock c in clockGroup) { ... }
}
catch (InvalidOperationException ex) when (ex.Message.Contains("invalidated"))
{
    // re-acquire enumerator and retry iteration
}

Prevention

When it happens

Trigger: Calling MoveNext (via foreach over a ClockGroup/ClockEnumerator) after the clock group's children collection was mutated or the clock tree was invalidated between obtaining the enumerator and advancing it.

Common situations: Iterating a ClockController/ClockGroup's clocks from a rendering or timing callback while animations are being added/removed or the storyboard hierarchy changes on another thread or during the same pass; holding an enumerator across animation tree rebuilds.

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/88780ec96d594225. Report an issue: GitHub.

Appendix: source

Thrown at src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/Animation/TimelineClockCollection.cs:386

            /// <returns>
            /// true if the enumerator was successfully advanced to the next
            /// element; false if the enumerator has passed the end of the
            /// collection.
            /// </returns>
            public bool MoveNext()
            {
                // If the collection is no longer empty, it means it was
                // modified and we should thrown an exception. Otherwise, we
                // are still valid, but the collection is empty so we should
                // just return false.

//                 _owner.VerifyAccess();

                ClockGroup clockGroup = _owner as ClockGroup;

                if (clockGroup != null && clockGroup.InternalChildren != null)
                {
                    throw new InvalidOperationException(SR.Timing_EnumeratorInvalidated);
                }

                return false;
            }

            #endregion // IEnumerator interface

            #region Internal implementation

            #region Data

            private Clock   _owner;

            #endregion // Data

            #endregion // Internal implementation
        }

View on GitHub (pinned to 81131a70a4)