dotnet/wpf · error · InvalidOperationException

Storyboard_UnableToFreeze

Storyboard_UnableToFreeze

Error message

SR.Storyboard_UnableToFreeze

What it means

BeginStoryboard.Seal throws InvalidOperationException (SR.Storyboard_UnableToFreeze) when the resolved Storyboard snapshot cannot be frozen. Sealing breaks thread affinity by freezing the storyboard; a storyboard holding unfreezable state (e.g. bound or dynamic values) prevents that.

Solutions

  1. Remove data bindings and DynamicResource references from the storyboard's animation values; use static values.
  2. Freeze any brushes, transforms, or keyframes used by the animations so the whole storyboard becomes freezable.
  3. Replace bound values with StaticResource references to pre-declared frozen resources.

Example fix

// before
<DoubleAnimation To="{Binding MaxOpacity}" Storyboard.TargetProperty="Opacity"/>
// after
<DoubleAnimation To="1.0" Storyboard.TargetProperty="Opacity"/>
Defensive patterns

Strategy: validation

Validate before calling

if (storyboard.CanFreeze)
    storyboard.Freeze();
else
    throw new InvalidOperationException("Storyboard contains unfreezable values (bindings/dynamic resources)");

Try / catch

try { template.Seal(); }
catch (InvalidOperationException ex) { /* storyboard not freezable; strip bindings */ }

Prevention

When it happens

Trigger: Sealing a BeginStoryboard whose Storyboard's CanFreeze returns false - typically because the storyboard's animations contain data bindings, DynamicResource references, or other expressions that block freezing.

Common situations: Storyboards with animated property values set via {Binding} or {DynamicResource} inside styles/templates, or animations using non-frozen brushes/gradients with mutable state.

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/5bd8f4dc48c80ece. Report an issue: GitHub.

Appendix: source

Thrown at src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Media/Animation/BeginStoryboard.cs:146

            // Gets our Storyboard value.  This value may have come from a
            //  ResourceReferenceExpression or might have been a deferred
            //  reference that has since been realized.
            Storyboard snapshot = GetValue(StoryboardProperty) as Storyboard;

            if( snapshot == null )
            {
                // This is the same error thrown by Begin if the Storyboard
                //  property couldn't be resolved at Begin time.  Since we're
                //  not allowing changes after this point, lack of resolution
                //  here means the same thing.
                throw new InvalidOperationException(SR.Storyboard_StoryboardReferenceRequired);
            }
            
            // We're planning to break our thread affinity - we also need to
            //  make sure the Storyboard can also be used accross threads.
            if(!snapshot.CanFreeze)
            {
                throw new InvalidOperationException(SR.Storyboard_UnableToFreeze);
            }
            if(!snapshot.IsFrozen)
            {
                snapshot.Freeze();
            }

            // Promote that snapshot into a local value.  This is a no-op if it
            //  was a deferred reference or local Storyboard, but if it came from a 
            //  ResourceReferenceExpression it will replace the Expression object
            //  with a snapshot of its current value.
            Storyboard = snapshot;
        }
        else
        {
            ; // base.Seal() will throw exception for us if already sealed.
        }

        base.Seal();        

View on GitHub (pinned to 81131a70a4)