dotnet/wpf · error · InvalidOperationException

SR.IAnimatable_CantAnimateSealedDO

Error message

SR.IAnimatable_CantAnimateSealedDO

What it means

Thrown by IAnimatable.ApplyAnimationClock when the target object IsSealed. Sealed (frozen/immutable) Freezable/DependencyObject instances cannot be modified, including having animation clocks applied.

Solutions

  1. Call Clone() or CloneCurrentValue() on the frozen object and animate the unfrozen clone.
  2. Ensure the source object is not frozen before animating (check Freezable.IsFrozen).
  3. Animate a different unfrozen instance, e.g. animate the element property instead of the shared frozen resource.

Example fix

// before
frozenBrush.ApplyAnimationClock(SolidColorBrush.ColorProperty, clock);
// after
var animatableBrush = frozenBrush.Clone();
animatableBrush.ApplyAnimationClock(SolidColorBrush.ColorProperty, clock);
Defensive patterns

Strategy: type-guard

Validate before calling

if (target is Freezable f && f.IsFrozen) target = f.Clone();

Type guard

static bool IsMutableForAnimation(DependencyObject o) => o is not Freezable f || !f.IsFrozen;

Try / catch

try { target.ApplyAnimationClock(dp, clock, handoff); } catch (InvalidOperationException ex) when (target is Freezable fz && fz.IsFrozen) { target = fz.Clone(); target.ApplyAnimationClock(dp, clock, handoff); }

Prevention

When it happens

Trigger: Calling ApplyAnimationClock on a frozen Freezable (e.g. a frozen Brush) or a sealed DependencyObject.

Common situations: Animating a Brush that was frozen via Freeze() for performance; sharing a frozen resource across elements and trying to animate it; animations targeting styles/resources marked frozen.

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


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

Appendix: source

Thrown at src/Microsoft.DotNet.Wpf/src/WpfGfx/codegen/mcg/generators/IAnimatableHelper.cs:94

                        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)