dotnet/wpf · error · InvalidOperationException
Storyboard_ImmutableTargetNotSupported
Storyboard_ImmutableTargetNotSupported
Error message
SR.Format(SR.Storyboard_ImmutableTargetNotSupported, path.Path)
What it means
The root target object of the animation property path itself is a frozen Freezable (path segment index 0), which cannot be animated. VerifyPathIsAnimatable throws this InvalidOperationException with the path — a distinct message from the intermediate-segment frozen error because nothing along the path can ever be mutable.
Solutions
- Target a live DependencyObject (e.g. the element), animating its property rather than the frozen object itself.
- Use CloneCurrentValue to obtain a mutable copy and register/apply the animation on that copy.
- Do not Freeze() objects intended as animation targets.
- Move the animation to the element property that owns the frozen value.
- Re-register the unfrozen instance under the same name before Begin.
Example fix
// before
var brush = (SolidColorBrush)FindResource("sharedBrush");
storyboard.Begin(brush); // brush is frozen
// after
var brush = new SolidColorBrush(((SolidColorBrush)FindResource("sharedBrush")).Color);
element.Fill = brush;
storyboard.Begin(element); Defensive patterns
Strategy: validation
Validate before calling
bool CanTarget(object o) => o is Freezable f ? !f.IsFrozen : o is DependencyObject;
Type guard
bool IsNotFrozenFreezable(object o) => !(o is Freezable f && f.IsFrozen);
Try / catch
try { storyboard.Begin(targetObject); }
catch (InvalidOperationException ex) when (ex.Message.Contains("immutable") || ex.Message.Contains("frozen"))
{
// resolve to a mutable clone or re-target a live DependencyObject
} Prevention
- Never register frozen Freezables as animation target names
- Target elements (DependencyObjects), not resource values
- Clone before animating shared/frozen resources
- Add pre-Begin assertion that target is not frozen
When it happens
Trigger: Storyboard.TargetName (or Target) resolves to an object that has been frozen — e.g. a Freezable registered as a resource, or a storyboard applied to a shared frozen resource instance rather than a UI element.
Common situations: Targeting a shared frozen Brush/Geometry resource directly; freezing a Freezable then using it as the animation target via RegisterName; static resources auto-frozen in some contexts then used as animation targets.
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.Storyboard_ImmutableTargetNotSupported…
- Storyboard_PropertyPathFrozenCheckFailed
- CannotChangeAfterSealed
- CannotChangeAfterSealed
- IAnimatable_CantAnimateSealedDO
AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14).
Data as JSON: /api/errors/0d2d16151d3d259c.
Report an issue: GitHub.
Appendix: source
Thrown at src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Media/Animation/Storyboard.cs:730
checkingFrozenState = false;
}
}
// Freezable objects (other than the one returned as the value of
// the first property) must not be frozen if the first one isn't.
else if( checkingFrozenState )
{
intermediateFreezable = intermediateObject as Freezable;
if( intermediateFreezable != null && intermediateFreezable.IsFrozen )
{
if( i > 0 )
{
throw new InvalidOperationException(SR.Format(SR.Storyboard_PropertyPathFrozenCheckFailed, AccessorName(path, i-1), path.Path, intermediateFreezable.GetType().ToString() ));
}
else
{
// i == 0 means the targeted object itself is a frozen Freezable.
// This need a different error message.
throw new InvalidOperationException(SR.Format(SR.Storyboard_ImmutableTargetNotSupported, path.Path));
}
}
}
// The last object + property pairing (the one we're actually going
// to stick the clock on) has further requirements.
if( i == path.Length-1 )
{
DependencyObject intermediateDO = intermediateObject as DependencyObject;
DependencyProperty intermediateDP = intermediateProperty as DependencyProperty;
if( intermediateDO == null )
{
Debug.Assert( i > 0, "The caller should not have set the PropertyPath context to a non DependencyObject." );
throw new InvalidOperationException(SR.Format(SR.Storyboard_PropertyPathMustPointToDependencyObject, AccessorName(path, i-1), path.Path));
}
if( intermediateDP == null )View on GitHub (pinned to 81131a70a4)