dotnet/wpf · error · InvalidOperationException
CannotChangeAfterSealed
CannotChangeAfterSealed
Error message
SR.Format(SR.CannotChangeAfterSealed, "BeginStoryboard")
What it means
BeginStoryboard.ThrowIfSealed throws InvalidOperationException (SR.CannotChangeAfterSealed for "BeginStoryboard") when any mutable property is changed after the object has been sealed. Sealing happens when the Triggers collection containing it is sealed, after which the action is immutable.
Solutions
- Create a new BeginStoryboard instance instead of mutating the sealed one.
- Make modifications before adding the BeginStoryboard to a Trigger's EnterActions/ExitActions or before the containing template is sealed.
- Clone the configuration into an unsealed object and replace it in the trigger.
Example fix
// before
sealedBeginStoryboard.HandoffBehavior = HandoffBehavior.Compose; // throws
// after
var newAction = new BeginStoryboard { Storyboard = storyboard, HandoffBehavior = HandoffBehavior.Compose };
trigger.EnterActions[0] = newAction; Defensive patterns
Strategy: try-catch
Validate before calling
if (!beginStoryboard.IsSealed)
beginStoryboard.HandoffBehavior = HandoffBehavior.Compose; Try / catch
try { beginStoryboard.Name = newName; }
catch (InvalidOperationException ex) { /* construct a replacement instead of mutating */ } Prevention
- Check IsSealed before mutating any BeginStoryboard property
- Configure triggers fully before adding to styles/templates that get sealed
- Treat sealed trigger actions as immutable; build new instances for changes
When it happens
Trigger: Setting Storyboard, HandoffBehavior, or Name on a BeginStoryboard whose IsSealed is true - e.g. mutating a template/event-trigger's BeginStoryboard after the containing style, template, or trigger collection was sealed.
Common situations: Modifying shared resources (styles/templates) at runtime that already contain BeginStoryboard actions, or reusing a cached BeginStoryboard instance across animations after it was sealed.
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/e5ab35d92b1028aa.
Report an issue: GitHub.
Appendix: source
Thrown at src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Media/Animation/BeginStoryboard.cs:117
{
ThrowIfSealed();
if(value != null && !System.Windows.Markup.NameValidationHelper.IsValidIdentifierName(value))
{
// Duplicate the error string thrown from DependencyObject.SetValueValidateParams
throw new ArgumentException(SR.Format(SR.InvalidPropertyValue, value, "Name"));
}
// Null is OK - it's to remove whatever name was previously set.
_name = value;
}
}
private void ThrowIfSealed()
{
if (IsSealed)
{
throw new InvalidOperationException(SR.Format(SR.CannotChangeAfterSealed, "BeginStoryboard"));
}
}
// Bug #1329664 workaround to make beta 2
// Remove thread affinity when sealed, but before doing that, snapshot the
// current Storyboard value and remove *its* thread affinity too.
internal override void Seal()
{
if( !IsSealed )
{
// 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 StoryboardView on GitHub (pinned to 81131a70a4)