dotnet/wpf · error · NotSupportedException

Timing_SlipBehavior_SlipOnlyOnSimpleTimelines

Timing_SlipBehavior_SlipOnlyOnSimpleTimelines

Error message

SR.Timing_SlipBehavior_SlipOnlyOnSimpleTimelines (Timing_SlipBehavior_SlipOnlyOnSimpleTimelines)

What it means

SlipBehavior.Slip is only supported on root clock trees with simple timelines: the root may not have a RepeatBehavior with a Duration, AutoReverse, or non-zero Acceleration/Deceleration ratios, otherwise child slipping cannot be tracked. BuildClockSubTreeFromTimeline throws NotSupportedException (Timing_SlipBehavior_SlipOnlyOnSimpleTimelines) when those conditions are violated.

Solutions

  1. Set SlipBehavior="Grow" (default) instead of Slip
  2. Remove AutoReverse, AccelerationRatio/DecelerationRatio, and duration-based RepeatBehavior from the root timeline
  3. Apply easing/acceleration to individual child animations instead of the slipping root
  4. Move the slipping media child into a simpler nested timeline structure

Example fix

// before
<Storyboard SlipBehavior="Slip" AutoReverse="True">
  <MediaTimeline Source="clip.wmv" />
</Storyboard> // throws
// after
<Storyboard SlipBehavior="Slip">
  <MediaTimeline Source="clip.wmv" />
</Storyboard>
Defensive patterns

Strategy: validation

Validate before calling

bool slipAllowed = timeline.SlipBehavior != SlipBehavior.Slip
    || !timeline.RepeatBehavior.HasDuration
    && !timeline.AutoReverse
    && timeline.AccelerationRatio == 0
    && timeline.DecelerationRatio == 0;
if (!slipAllowed) timeline.SlipBehavior = SlipBehavior.Grow;

Try / catch

try { storyboard.Begin(this, true); }
catch (NotSupportedException ex) when (ex.Message.Contains("Slip")) { /* switch SlipBehavior to Grow and retry */ }

Prevention

When it happens

Trigger: Creating a Clock/Storyboard with SlipBehavior="Slip" on a timeline that also sets RepeatBehavior with Duration, AutoReverse="True", AccelerationRatio>0, or DecelerationRatio>0 (on the root).

Common situations: Combining video MediaTimeline slipping with eased/fancied-up root timelines; applying global storyboard easing or looping (RepeatBehavior="2x"/AutoReverse) to a storyboard that contains a media child with slip.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


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

Appendix: source

Thrown at src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/Animation/ClockGroup.cs:127

                    childClock = AllocateClock(timelineChildren[index], hasControllableRoot);
                    childClock._parent = this;  // We connect the child to the subtree before calling BuildClockSubtreeFromTimeline
                    childClock.BuildClockSubTreeFromTimeline(timelineChildren[index], hasControllableRoot);
                    _children.Add(childClock);
                    childClock._childIndex = index;
                }

                // If we have SlipBehavior, check if we have any childen with which to slip.
                if (_timeline is ParallelTimeline &&
                    ((ParallelTimeline)_timeline).SlipBehavior == SlipBehavior.Slip)
                {
                    // Verify that we only use SlipBehavior in supported scenarios
                    if (!IsRoot ||
                       (_timeline.RepeatBehavior.HasDuration) ||
                       (_timeline.AutoReverse) ||
                       (_timeline.AccelerationRatio > 0) ||
                       (_timeline.DecelerationRatio > 0))
                    {
                        throw new NotSupportedException(SR.Timing_SlipBehavior_SlipOnlyOnSimpleTimelines);
                    }

                    for (int index = 0; index < _children.Count; index++)
                    {
                        Clock child = _children[index];
                        if (child.CanSlip)
                        {
                            Duration duration = child.ResolvedDuration;

                            // A sync clock with duration of zero or no begin time has no effect, so do skip it
                            if ((!duration.HasTimeSpan || duration.TimeSpan > TimeSpan.Zero)
                                && child._timeline.BeginTime.HasValue)
                            {
                                _syncData = new SyncData(child);
                                child._syncData = null;  // The child will no longer self-sync
                            }

                            break;  // We only want the first child with CanSlip

View on GitHub (pinned to 81131a70a4)