dotnet/wpf · error · InvalidOperationException

Timing_CreateClockMustReturnNewClock

Timing_CreateClockMustReturnNewClock

Error message

SR.Timing_CreateClockMustReturnNewClock (Timing_CreateClockMustReturnNewClock)

What it means

AllocateClock verified that the Clock returned by a Timeline-derived class's CreateClock override is brand new: not already parented and not already attached to a clock group's children. A recycled or shared clock fails this invariant and WPF throws InvalidOperationException.

Solutions

  1. Always create a fresh Clock instance in the CreateClock override
  2. Remove clock caching/pooling from custom Timeline subclasses
  3. Verify the custom clock constructor does not attach itself to a parent or group

Example fix

// before
public override Clock CreateClock() => _cachedClock ??= base.CreateClock(); // throws on reuse
// after
public override Clock CreateClock() => base.CreateClock();
Defensive patterns

Strategy: validation

Validate before calling

Debug.Assert(myClock.Parent == null, "Clock must be fresh, not reused");

Try / catch

try { var clock = timeline.CreateClock(); } catch (InvalidOperationException ex) { log.Error(ex); }

Prevention

When it happens

Trigger: Overriding CreateClock in a custom Timeline and returning a cached/shared Clock instance; calling CreateClock twice and reusing the first result.

Common situations: Custom timeline implementations that pool clocks for performance; factory code accidentally reusing a clock across timelines.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


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

Appendix: source

Thrown at src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/Animation/Clock.cs:582

        internal static Clock AllocateClock(
            Timeline timeline,
            bool hasControllableRoot)
        {
            Clock clock = timeline.AllocateClock();

            // Assert that we weren't given an existing clock
            Debug.Assert(!clock.IsTimeManager);

            ClockGroup clockGroup = clock as ClockGroup;

            if (   clock._parent != null
                || (   clockGroup != null
                    && clockGroup.InternalChildren != null ))
            {
                // The derived class is trying to fool us -- we require a new,
                // fresh, unassociated clock here
                throw new InvalidOperationException(
                    SR.Format(
                        SR.Timing_CreateClockMustReturnNewClock,
                        timeline.GetType().Name));
            }

            clock.SetFlag(ClockFlags.HasControllableRoot, hasControllableRoot);

            return clock;
        }

        internal virtual void BuildClockSubTreeFromTimeline(
            Timeline timeline,
            bool hasControllableRoot)
        {
            SetFlag(ClockFlags.CanSlip, GetCanSlip());  // Set the CanSlip flag

            // Here we preview the clock's own slip-ability, hence ClockGroups should return false
            // at this stage, because their children are not yet added by the time of this call.

View on GitHub (pinned to 81131a70a4)