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
- Clone the frozen object first: var clone = frozenBrush.Clone(); then animate the clone and assign it back to the target property.
- Use CloneCurrentValue() to preserve current animated values before unfreezing.
- 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
- Check IsFrozen before animating Freezables.
- Never freeze objects you plan to animate.
- Clone resources fetched from shared dictionaries before animating them.
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
- SR.Format(SR.IAnimatable_CantAnimateSealedDO, dp…
- SR.Format(SR.Storyboard_ImmutableTargetNotSupported…
- SR.IAnimatable_CantAnimateSealedDO
- SR.IAnimatable_CantAnimateSealedDO (formatted with dp and…
- SR.IAnimatable_CantAnimateSealedDO
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)