dotnet/wpf · error · InvalidOperationException
Storyboard_PropertyPathFrozenCheckFailed
Storyboard_PropertyPathFrozenCheckFailed
Error message
SR.Format(SR.Storyboard_PropertyPathFrozenCheckFailed, AccessorName(path, i-1), path.Path, intermediateFreezable.GetType().ToString())
What it means
An intermediate object along the animation property path is a frozen (immutable) Freezable, so Storyboard cannot traverse or modify through it. VerifyPathIsAnimatable throws this InvalidOperationException naming the accessor, path, and the frozen type.
Solutions
- Clone the frozen Freezable via CloneCurrentValue and target the unfrozen copy (e.g. assign a mutable brush to the element first).
- Avoid calling Freeze() on objects whose sub-properties you animate.
- Change the target to an unfrozen equivalent resource.
- Assign a new live instance (element.Fill = new SolidColorBrush(...)) and animate that instead.
- Restructure the path so it does not pass through the frozen object.
Example fix
// before brush.Freeze(); element.Fill = brush; storyboard.Begin(element); // animates (SolidColorBrush.Color) // after var animatableBrush = brush.CloneCurrentValue(); element.Fill = animatableBrush; // keep unfrozen storyboard.Begin(element);
Defensive patterns
Strategy: validation
Validate before calling
static bool PathObjectsUnfrozen(PropertyPath path, object root)
{
path.Evaluate(root);
for (int i = 0; i < path.Get getItemCount; i++)
{
if (path.GetItem(i) is Freezable f && f.IsFrozen) return false;
}
return true;
} Type guard
bool IsAnimatableFreezable(object o) => !(o is Freezable f && f.IsFrozen);
Try / catch
try { storyboard.Begin(element); }
catch (InvalidOperationException ex) when (ex.Message.Contains("frozen") || ex.Message.Contains("Frozen"))
{
// clone the frozen object and retry with mutable instance
} Prevention
- Never Freeze objects whose sub-properties will be animated
- CloneCurrentValue before animating shared resources
- Keep animated brushes/geometries as live instances
- Audit resource dictionaries for frozen resources used in animations
When it happens
Trigger: A path traverses a Freezable that was Freeze()d or auto-frozen (e.g. a frozen Brush or Geometry) and the animation needs to set a sub-property through it, with segment index i > 0.
Common situations: Animating (SolidColorBrush.Color) on a brush that was frozen for performance or declared in a resource dictionary that froze it; frozen Geometry/Transform collections in paths; freezing objects after cross-thread use then animating their sub-properties.
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
- Storyboard_ImmutableTargetNotSupported
- Storyboard_PropertyPathEmpty
- Storyboard_PropertyPathMustPointToDependencyObject
- Storyboard_PropertyPathMustPointToDependencyProperty
- Storyboard_PropertyPathObjectNotFound
AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14).
Data as JSON: /api/errors/d1267014341e21fa.
Report an issue: GitHub.
Appendix: source
Thrown at src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Media/Animation/Storyboard.cs:724
// Object 0 is the Button, object 1 is the brush.
if( i == 1 )
{
intermediateFreezable = intermediateObject as Freezable;
if( intermediateFreezable != null && intermediateFreezable.IsFrozen )
{
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 )View on GitHub (pinned to 81131a70a4)