dotnet/wpf · error · InvalidOperationException

IAnimatable_CantAnimateSealedDO

IAnimatable_CantAnimateSealedDO

Error message

SR.IAnimatable_CantAnimateSealedDO (IAnimatable_CantAnimateSealedDO)

What it means

ApplyAnimationClock was called on a Freezable/Animatable that is currently sealed (frozen). Sealed objects are immutable, so WPF throws an InvalidOperationException — you cannot add animation clocks to them. Animating requires a mutable (unfrozen, unsealed) instance.

Solutions

  1. Clone the frozen object first: var clone = frozenBrush.Clone(); then animate the clone and assign it back to the target property.
  2. Use CloneCurrentValue() to preserve current animated values before unfreezing.
  3. Avoid calling Freeze() on objects you intend to animate.

Example fix

// before
myRect.Fill.ApplyAnimationClock(SolidColorBrush.ColorProperty, clock); // Fill is frozen Brushes.Red
// after
var brush = ((SolidColorBrush)myRect.Fill).Clone();
myRect.Fill = brush;
brush.ApplyAnimationClock(SolidColorBrush.ColorProperty, clock);
Defensive patterns

Strategy: validation

Validate before calling

if (animatable is Freezable f && f.IsFrozen)
{
    var clone = f.CloneCurrentValue();
    targetProperty.SetValue(owner, clone);
    animatable = clone;
}

Type guard

static bool CanAnimate(DependencyObject o) => o is Freezable f ? !f.IsFrozen : !((Animatable)o).IsSealed;

Try / catch

try { animatable.ApplyAnimationClock(dp, clock); }
catch (InvalidOperationException) { animatable = ((Freezable)animatable).Clone(); /* retry on clone */ }

Prevention

When it happens

Trigger: Calling ApplyAnimationClock on a frozen brush/pen/geometry (e.g. Brushes.Red, a frozen Freezable obtained from a resource or from FindResource) or on any object whose IsSealed/IsFrozen is true.

Common situations: Animating system-provided frozen brushes (Brushes.*, SystemColors.*Brush); sharing a single Freezable across many visuals after calling Freeze(); animating a resource-retrieved brush without cloning.

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

Appendix: source

Thrown at src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/Animation/Generated/Animatable.cs:86

            if (!AnimationStorage.IsPropertyAnimatable(this, dp))
            {
                throw new ArgumentException(SR.Format(SR.Animation_DependencyPropertyIsNotAnimatable, dp.Name, this.GetType()), nameof(dp));
            }

            if (clock != null
                && !AnimationStorage.IsAnimationValid(dp, clock.Timeline))
            {
                throw new ArgumentException(SR.Format(SR.Animation_AnimationTimelineTypeMismatch, clock.Timeline.GetType(), dp.Name, dp.PropertyType), nameof(clock));
            }

            if (!HandoffBehaviorEnum.IsDefined(handoffBehavior))
            {
                throw new ArgumentException(SR.Animation_UnrecognizedHandoffBehavior);
            }

            if (IsSealed)
            {
                throw new InvalidOperationException(SR.Format(SR.IAnimatable_CantAnimateSealedDO, dp, this.GetType()));
            }

            AnimationStorage.ApplyAnimationClock(this, dp, clock, handoffBehavior);
        }

        /// <summary>
        /// Starts an animation for a DependencyProperty. The animation will
        /// begin when the next frame is rendered.
        /// </summary>
        /// <param name="dp">
        /// The DependencyProperty to animate.
        /// </param>
        /// <param name="animation">
        /// <para>The AnimationTimeline to used to animate the property.</para>
        /// <para>If the AnimationTimeline's BeginTime is null, any current animations
        /// will be removed and the current value of the property will be held.</para>
        /// <para>If this value is null, all animations will be removed from the property
        /// and the property value will revert back to its base value.</para>

View on GitHub (pinned to 81131a70a4)