dotnet/wpf · error · InvalidOperationException
SR.IAnimatable_CantAnimateSealedDO
Error message
SR.IAnimatable_CantAnimateSealedDO
What it means
Once a DependencyObject is sealed (immutable, e.g. a frozen Freezable or a sealed template/resource instance), animations can no longer be applied to it. Visual3D.ApplyAnimationClock checks IsSealed and throws InvalidOperationException with IAnimatable_CantAnimateSealedDO. Sealing is a WPF mechanism to make objects thread-safe and immutable; mutation via animation is disallowed.
Solutions
- Call Clone() (or CloneCurrentValue()) on the frozen/sealed object and apply the animation to the clone.
- Declare the target as a mutable instance (x:Shared resources or code-created objects) instead of a frozen shared resource.
- Delay any Freeze() call until animations no longer need to be applied to the object.
Example fix
// before
var transform = (RotateTransform3D)FindResource("spinTransform");
transform.ApplyAnimationClock(...); // sealed/frozen
// after
var transform = ((RotateTransform3D)FindResource("spinTransform")).Clone();
transform.ApplyAnimationClock(...); Defensive patterns
Strategy: validation
Validate before calling
if (target.IsSealed)
{
target = (Visual3D)((Freezable)target).GetAsFrozen is null ? target : CloneForAnimation(target);
}
target.ApplyAnimationClock(dp, clock, behavior); Type guard
static bool CanAnimate(Visual3D v) => !v.IsSealed;
Try / catch
try { visual.ApplyAnimationClock(dp, clock, behavior); }
catch (InvalidOperationException ex) when (ex.Message.Contains("sealed")) { var clone = CloneForAnimation(visual); clone.ApplyAnimationClock(dp, clock, behavior); } Prevention
- Defer Freeze() on any Freezable/Visual3D until animations are no longer applied.
- Never animate objects obtained via StaticResource without cloning first.
- Assert !IsSealed in animation setup helpers.
When it happens
Trigger: Calling ApplyAnimationClock on a Visual3D (or its transforms/materials) that has been sealed — commonly after Freeze() was called on an associated Freezable, or the object came from a sealed resource/template instance.
Common situations: Animating a frozen Transform3D shared via a StaticResource; objects declared in a ResourceDictionary that WPF sealed; performance-driven Freeze() calls made before animations are attached.
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
- SR.Format(SR.Storyboard_ImmutableTargetNotSupported…
- Animation_Invalid_DefaultValue
- IAnimatable_CantAnimateSealedDO
- SR.Animation_Invalid_DefaultValue
- SR.Animation_NoTextChildren
AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14).
Data as JSON: /api/errors/fbe20a8cefa397c2.
Report an issue: GitHub.
Appendix: source
Thrown at src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media3D/Generated/Visual3D.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)