{"record":{"id":"ab2987495a3f4f19","repo":"dotnet/wpf","slug":"storyboard-propertypathsealedcheckfailed","errorCode":"Storyboard_PropertyPathSealedCheckFailed","errorMessage":"SR.Format(SR.Storyboard_PropertyPathSealedCheckFailed, intermediateDP.Name, path.Path, intermediateDO)","messagePattern":"SR\\.Format\\(SR\\.Storyboard_PropertyPathSealedCheckFailed, intermediateDP\\.Name, path\\.Path, intermediateDO\\)","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Media/Animation/Storyboard.cs","lineNumber":755,"sourceCode":"            if( i == path.Length-1 )\n            {\n                DependencyObject intermediateDO = intermediateObject as DependencyObject;\n                DependencyProperty intermediateDP = intermediateProperty as DependencyProperty;\n\n                if( intermediateDO == null )\n                {\n                    Debug.Assert( i > 0, \"The caller should not have set the PropertyPath context to a non DependencyObject.\" );\n                    throw new InvalidOperationException(SR.Format(SR.Storyboard_PropertyPathMustPointToDependencyObject, AccessorName(path, i-1), path.Path));\n                }\n\n                if( intermediateDP == null )\n                {\n                    throw new InvalidOperationException(SR.Format(SR.Storyboard_PropertyPathMustPointToDependencyProperty, path.Path ));\n                }\n\n                if( checkingFrozenState && intermediateDO.IsSealed )\n                {\n                    throw new InvalidOperationException(SR.Format(SR.Storyboard_PropertyPathSealedCheckFailed, intermediateDP.Name, path.Path, intermediateDO));\n                }\n\n                if(!AnimationStorage.IsPropertyAnimatable(intermediateDO, intermediateDP) )\n                {\n                    throw new InvalidOperationException(SR.Format(SR.Storyboard_PropertyPathIncludesNonAnimatableProperty, path.Path, intermediateDP.Name));\n                }\n            }\n        }\n    }\n\n    private static string AccessorName( PropertyPath path, int index )\n    {\n        object propertyAccessor = path.GetAccessor(index);\n\n        if( propertyAccessor is DependencyProperty )\n        {\n            return ((DependencyProperty)propertyAccessor).Name;\n        }","sourceCodeStart":737,"sourceCodeEnd":773,"githubUrl":"https://github.com/dotnet/wpf/blob/81131a70a4c573cd62748a5c36908fc4d662daa9/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Media/Animation/Storyboard.cs#L737-L773","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Clone the sealed object (CloneCurrentValue) and use the mutable clone in the path.","Remove Freeze() calls on objects used as animation path intermediates.","Target the owning element property instead of the sealed object's sub-property.","Substitute an unfrozen resource instance.","Restructure the path to avoid the sealed intermediate."],"exampleFix":"// before\ngeometry.Freeze();\nstoryboard.Begin(element); // path: (Path.Data).(PathGeometry.Figures)[0]...\n// after\nvar animGeometry = geometry.CloneCurrentValue(); // stays unsealed\npathElement.Data = animGeometry;\nstoryboard.Begin(element);","handlingStrategy":"validation","validationCode":"bool PathFreeOfSealed(object root, PropertyPath path)\n{\n    try {\n        path.Evaluate(root);\n        for (int i = 0; i < path.Get getItemCount; i++)\n            if (path.GetItem(i) is Freezable f && f.IsSealed) return false;\n        return true;\n    } catch { return false; }\n}","typeGuard":"bool IsUnsealed(object o) => !(o is Freezable f && f.IsSealed);","tryCatchPattern":"try { storyboard.Begin(element); }\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"sealed\"))\n{\n    // swap in CloneCurrentValue() of the sealed object, then retry\n}","preventionTips":["Avoid Freeze on objects used as animation path intermediates","CloneCurrentValue shared resources before animating their sub-properties","Keep animation-path objects mutable for their lifetime","Verify IsSealed==false in debug before Begin"],"tags":["wpf","freezable","sealed","propertypath"],"backgroundTag":"invalid-state-transition","analyzedSha":"81131a70a4c573cd62748a5c36908fc4d662daa9","analyzedAt":"2026-09-14T10:12:48.479Z","contentChangedAt":"2026-09-14T10:12:48.479Z","schemaVersion":2},"datasetVersion":"2026-09-21T21:30:21.729Z"}