dotnet/wpf · error · InvalidOperationException

Storyboard_PropertyPathSealedCheckFailed

Storyboard_PropertyPathSealedCheckFailed

Error message

SR.Format(SR.Storyboard_PropertyPathSealedCheckFailed, intermediateDP.Name, path.Path, intermediateDO)

What it means

During frozen-state checking, if an intermediate DependencyObject in the property path is sealed (a Freezable that has been sealed via Freeze), it cannot have animation clocks attached through it. VerifyPathIsAnimatable throws this InvalidOperationException naming the DependencyProperty, path, and sealed object.

Solutions

  1. Clone the sealed object (CloneCurrentValue) and use the mutable clone in the path.
  2. Remove Freeze() calls on objects used as animation path intermediates.
  3. Target the owning element property instead of the sealed object's sub-property.
  4. Substitute an unfrozen resource instance.
  5. Restructure the path to avoid the sealed intermediate.

Example fix

// before
geometry.Freeze();
storyboard.Begin(element); // path: (Path.Data).(PathGeometry.Figures)[0]...
// after
var animGeometry = geometry.CloneCurrentValue(); // stays unsealed
pathElement.Data = animGeometry;
storyboard.Begin(element);
Defensive patterns

Strategy: validation

Validate before calling

bool PathFreeOfSealed(object root, PropertyPath path)
{
    try {
        path.Evaluate(root);
        for (int i = 0; i < path.Get getItemCount; i++)
            if (path.GetItem(i) is Freezable f && f.IsSealed) return false;
        return true;
    } catch { return false; }
}

Type guard

bool IsUnsealed(object o) => !(o is Freezable f && f.IsSealed);

Try / catch

try { storyboard.Begin(element); }
catch (InvalidOperationException ex) when (ex.Message.Contains("sealed"))
{
    // swap in CloneCurrentValue() of the sealed object, then retry
}

Prevention

When it happens

Trigger: Storybard.TargetProperty path passes through a sealed Freezable DependencyObject while the storyboard validates frozen state — typically a frozen Brush/Geometry intermediate whose sub-property is being animated.

Common situations: Animating a sub-property of a frozen shared resource (Color of a frozen brush); resource-dictionary brushes frozen after use across threads; cloning not performed before Begin.

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


AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14). Data as JSON: /api/errors/ab2987495a3f4f19. Report an issue: GitHub.

Appendix: source

Thrown at src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Media/Animation/Storyboard.cs:755

            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 )
                {
                    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;
        }

View on GitHub (pinned to 81131a70a4)