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
- Snapshot the clocks into a list (e.g. clockGroup.Children.ToList()) before iterating so enumeration does not depend on live internal state
- Re-fetch a fresh enumerator after any change to the clock/storyboard tree instead of reusing the old one
- Perform all clock-tree mutations and enumerations on the same thread and outside of active enumeration
- 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
- Snapshot the clock collection before iterating
- Never hold clock enumerators across storyboard/clock-tree mutations
- Enumerate and mutate the clock tree on the same thread
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
- SR.Enumerator_CollectionChanged
- SR.Enumerator_CollectionChanged
- Animation_AnimationTimelineTypeMismatch
- Animation_CalculatedValueIsInvalidForProperty
- Animation_ChildMustBeKeyFrame
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)