dotnet/wpf · error · InvalidOperationException
CannotChangeAfterSealed
CannotChangeAfterSealed
Error message
SR.Format(SR.CannotChangeAfterSealed, "ControllableStoryboardAction")
What it means
ControllableStoryboardAction.BeginStoryboardName throws InvalidOperationException (SR.CannotChangeAfterSealed for "ControllableStoryboardAction") when the name is changed after the action is sealed. The name links a control action (Pause/Resume/Stop) to a BeginStoryboard, and sealed actions are immutable.
Solutions
- Create a new ControllableStoryboardAction instance with the desired BeginStoryboardName.
- Set BeginStoryboardName before adding the action to the Trigger or before the containing template seals.
- Replace the sealed action in the trigger's actions collection with a fresh, configured one.
Example fix
// before
sealedPauseAction.BeginStoryboardName = "begin"; // throws
// after
var pauseAction = new PauseStoryboard { BeginStoryboardName = "begin" };
trigger.Actions[0] = pauseAction; Defensive patterns
Strategy: try-catch
Validate before calling
if (!controlAction.IsSealed)
controlAction.BeginStoryboardName = "begin"; Try / catch
try { controlAction.BeginStoryboardName = name; }
catch (InvalidOperationException ex) { /* create a new action instance instead */ } Prevention
- Check IsSealed before changing BeginStoryboardName on control actions
- Match BeginStoryboardName exactly to the BeginStoryboard's Name (including x:Name registration)
- Rebuild control actions rather than mutating shared sealed instances
When it happens
Trigger: Setting BeginStoryboardName on a PauseStoryboard/ResumeStoryboard/SeekStoryboard/StopStoryboard whose IsSealed is true - i.e. after its containing trigger collection was sealed.
Common situations: Mutating shared style/template storyboard control actions at runtime, or reusing a cached control action instance after it has been used in a sealed template.
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
- CannotChangeAfterSealed
- CannotChangeAfterSealed
- CannotChangeAfterSealed
- SR.InvalidPropertyValue formatted with (value, "Name") -…
- SR.Storyboard_UnrecognizedHandoffBehavior (unrecognized…
AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14).
Data as JSON: /api/errors/4949a7ac8725a2c3.
Report an issue: GitHub.
Appendix: source
Thrown at src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Media/Animation/ControllableStoryboardAction.cs:48
{
}
/// <summary>
/// Name to use for resolving the storyboard reference needed. This
/// points to a BeginStoryboard instance, and we're controlling that one.
/// </summary>
[DefaultValue(null)]
public string BeginStoryboardName
{
get
{
return _beginStoryboardName;
}
set
{
if (IsSealed)
{
throw new InvalidOperationException(SR.Format(SR.CannotChangeAfterSealed, "ControllableStoryboardAction"));
}
// Null is allowed to wipe out existing name - as long as another
// valid name is set before Invoke time.
_beginStoryboardName = value;
}
}
internal sealed override void Invoke( FrameworkElement fe, FrameworkContentElement fce, Style targetStyle, FrameworkTemplate frameworkTemplate, Int64 layer )
{
Debug.Assert( fe != null || fce != null, "Caller of internal function failed to verify that we have a FE or FCE - we have neither." );
Debug.Assert( targetStyle != null || frameworkTemplate != null,
"This function expects to be called when the associated action is inside a Style/Template. But it was not given a reference to anything." );
INameScope nameScope = null;
if( targetStyle != null )
{
nameScope = targetStyle;View on GitHub (pinned to 81131a70a4)