dotnet/wpf · error · NotSupportedException

Timing_CanSlipOnlyOnSimpleTimelines

Timing_CanSlipOnlyOnSimpleTimelines

Error message

SR.Timing_CanSlipOnlyOnSimpleTimelines (Timing_CanSlipOnlyOnSimpleTimelines)

What it means

A timeline with CanSlip (e.g. MediaTimeline) using SlipBehavior=Slip only supports 'simple' timing. BuildClockSubTreeFromTimeline throws NotSupportedException when the slipping timeline itself has AutoReverse=true or AccelerationRatio/DecelerationRatio > 0.

Solutions

  1. Remove AutoReverse or reset AccelerationRatio/DecelerationRatio to 0 on the slipping timeline
  2. Use default SlipBehavior (Grow) if advanced timing effects are needed
  3. Simulate reverse playback via Seek instead of AutoReverse on media timelines

Example fix

// before
var media = new MediaTimeline { Source = uri, SlipBehavior = SlipBehavior.Slip, AutoReverse = true }; // throws
// after
var media = new MediaTimeline { Source = uri, SlipBehavior = SlipBehavior.Slip };
Defensive patterns

Strategy: validation

Validate before calling

bool slipSafe = !media.AutoReverse && media.AccelerationRatio == 0 && media.DecelerationRatio == 0;
if (!slipSafe) media.SlipBehavior = SlipBehavior.Grow;

Prevention

When it happens

Trigger: Creating a clock tree from a MediaTimeline (or other CanSlip timeline) with SlipBehavior=Slip while that timeline has AutoReverse=true or AccelerationRatio/DecelerationRatio > 0.

Common situations: Adding easing/acceleration to media-synced animations; setting AutoReverse on a MediaTimeline expecting rewind behavior.

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

Appendix: source

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

            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.
            if (CanSlip && (IsRoot || _timeline.BeginTime.HasValue))
            {
                ResolveDuration();

                // A sync clock with duration of zero or no begin time has no effect, so do skip it
                if (!_resolvedDuration.HasTimeSpan || _resolvedDuration.TimeSpan > TimeSpan.Zero)
                {
                    // Verify that we only use SlipBehavior in supported scenarios
                    if ((_timeline.AutoReverse) ||
                        (_timeline.AccelerationRatio > 0) ||
                        (_timeline.DecelerationRatio > 0))
                    {
                        throw new NotSupportedException(SR.Timing_CanSlipOnlyOnSimpleTimelines);
                    }

                    _syncData = new SyncData(this);  // CanSlip clocks keep themselves synced
                    HasDescendantsWithUnresolvedDuration = !HasResolvedDuration;  // Keep track of when our duration is resolved

                    Clock current = _parent;  // Traverse up the parent chain and verify that no unsupported behavior is specified
                    while (current != null)
                    {
                        Debug.Assert(!current.IsTimeManager);  // We should not yet be connected to the TimeManager
                        if (current._timeline.AutoReverse || current._timeline.AccelerationRatio > 0
                                                          || current._timeline.DecelerationRatio > 0)
                        {
                            throw new System.InvalidOperationException(SR.Timing_SlipBehavior_SyncOnlyWithSimpleParents);
                        }

                        current.SetFlag(ClockFlags.CanGrow, true);  // Propagate the slippage tracking up the tree
                        if (!HasResolvedDuration)  // Let the parents know that we have not yet unresolved duration
                        {

View on GitHub (pinned to 81131a70a4)