dotnet/wpf · error · InvalidOperationException
Storyboard_PropertyPathIncludesNonAnimatableProperty
Storyboard_PropertyPathIncludesNonAnimatableProperty
Error message
SR.Format(SR.Storyboard_PropertyPathIncludesNonAnimatableProperty, path.Path, intermediateDP.Name)
What it means
Every property along the animation property path must be animatable — AnimationStorage.IsPropertyAnimatable must accept it. VerifyPathIsAnimatable throws this InvalidOperationException when an intermediate or final DependencyProperty (named in the message) cannot host an AnimationClock (e.g. read-only or wrong value type).
Solutions
- Change the path property to an animatable one (e.g. Width instead of ActualWidth).
- Match the AnimationTimeline type to the DP's PropertyType (DoubleAnimation for double DPs, ColorAnimation for Color, etc.).
- For read-only DPs, animate the property that drives them instead.
- For custom DPs, ensure the type has a corresponding AnimationTimeline and the property is animatable.
- Wrap the value in an animatable DP and animate that.
Example fix
// before
new PropertyPath("(FrameworkElement.ActualWidth)"); // read-only, not animatable
// after
new PropertyPath("(FrameworkElement.Width)"); Defensive patterns
Strategy: validation
Validate before calling
bool CheckAnimatable(DependencyObject d, DependencyProperty p) =>
AnimationStorage.IsPropertyAnimatable(d, p); // or reflect: !p.ReadOnly && p.GetMetadata(d.GetType()).TypeKey != null Type guard
bool IsAnimatableProperty(DependencyObject d, DependencyProperty p) =>
!p.ReadOnly && AnimationStorage.IsPropertyAnimatable(d, p); Try / catch
try { storyboard.Begin(target); }
catch (InvalidOperationException ex) when (ex.Message.Contains("not animatable"))
{
// substitute an animatable property for the one named in the message
} Prevention
- Never animate read-only properties (ActualWidth, ActualHeight)
- Match animation class to the DP's PropertyType
- Consult animatable properties list in WPF docs per control
- For custom DPs, verify a matching AnimationTimeline exists
When it happens
Trigger: Storybard.TargetProperty references a DependencyProperty that is not animatable — read-only DPs, DPs whose type has no matching AnimationTimeline, or non-animatable metadata (CannotBeAnimated).
Common situations: Animating read-only properties like ActualWidth; animating a DP whose PropertyType has no corresponding animation type (e.g. animating a complex object DP with a DoubleAnimation); animating properties on custom DPs registered without animatable types.
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_PropertyPathObjectNotFound
- Storyboard_PropertyPathPropertyNotFound
- Animation_AnimationTimelineTypeMismatch
- Animation_CalculatedValueIsInvalidForProperty
- Animation_ChildMustBeKeyFrame
AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14).
Data as JSON: /api/errors/a5abfedb5dd76183.
Report an issue: GitHub.
Appendix: source
Thrown at src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Media/Animation/Storyboard.cs:760
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 )
{
throw new InvalidOperationException(SR.Format(SR.Storyboard_PropertyPathMustPointToDependencyProperty, path.Path ));
}
if( checkingFrozenState && intermediateDO.IsSealed )
{
throw new InvalidOperationException(SR.Format(SR.Storyboard_PropertyPathSealedCheckFailed, intermediateDP.Name, path.Path, intermediateDO));
}
if(!AnimationStorage.IsPropertyAnimatable(intermediateDO, intermediateDP) )
{
throw new InvalidOperationException(SR.Format(SR.Storyboard_PropertyPathIncludesNonAnimatableProperty, path.Path, intermediateDP.Name));
}
}
}
}
private static string AccessorName( PropertyPath path, int index )
{
object propertyAccessor = path.GetAccessor(index);
if( propertyAccessor is DependencyProperty )
{
return ((DependencyProperty)propertyAccessor).Name;
}
else if( propertyAccessor is PropertyInfo )
{
return ((PropertyInfo)propertyAccessor).Name;
}
else if( propertyAccessor is PropertyDescriptor )View on GitHub (pinned to 81131a70a4)