dotnet/wpf · error · InvalidOperationException

Storyboard_TargetNameNotAllowedInStyle

Storyboard_TargetNameNotAllowedInStyle

Error message

SR.Format(SR.Storyboard_TargetNameNotAllowedInStyle, nameString)

What it means

During ClockTreeWalkRecursive (invoked from Storyboard.Begin), a timeline has a TargetName while the current namescope is a Style. Styles forbid targeting other objects — animations inside a Style may only affect the styled (implicit target) object — so any TargetName is rejected with an InvalidOperationException.

Solutions

  1. Remove TargetName (and Target) from the timeline in the Style; the animation implicitly targets the styled element — specify only Storyboard.TargetProperty.
  2. Move the storyboard to Window/UserControl resources and trigger it via EventTrigger with SourceName if cross-element targeting is required.
  3. Use a ControlTemplate trigger with TargetName if targeting named template parts (allowed in templates, not styles).

Example fix

<!-- before: throws -->
<Style TargetType="Button">
  <Style.Triggers>
    <Trigger Property="IsMouseOver" Value="True">
      <Trigger.EnterActions>
        <Storyboard>
          <DoubleAnimation Storyboard.TargetName="otherPanel" Storyboard.TargetProperty="Opacity" To="1"/>
        </Storyboard>
      </Trigger.EnterActions>
    </Trigger>
  </Style.Triggers>
</Style>

<!-- after: implicit target only -->
<DoubleAnimation Storyboard.TargetProperty="Opacity" To="1"/>
Defensive patterns

Strategy: validation

Validate before calling

// In a Style, fail fast if a timeline declares TargetName
if (inStyle && timeline.GetValue(Storyboard.TargetNameProperty) != null)
    throw new InvalidOperationException("Storyboard.TargetName is not allowed inside a Style");

Try / catch

try { BeginStoryboard(); }
catch (InvalidOperationException ex) when (ex.Message.Contains("Style")) {
    // remove TargetName or move the storyboard out of the Style
}

Prevention

When it happens

Trigger: Defining a Storyboard inside a <Style> (Setters/Triggers/EnterActions/ExitActions) where a child timeline sets Storyboard.TargetName="someElement", then beginning the storyboard via trigger actions.

Common situations: Trying to animate another control from a Style trigger; porting a storyboard from Window resources into a Style without removing TargetName; misunderstanding that Style animations implicitly target the styled element.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


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

Appendix: source

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

        Int64 layer                        /* Remains the same through all the recursive calls */)
    {
        Timeline currentTimeline = currentClock.Timeline;

        DependencyObject targetObject = parentObject;
        string currentObjectName = parentObjectName;
        PropertyPath currentPropertyPath = parentPropertyPath;

        // If we have target object/property information, use it instead of the
        //  parent's information.
        string nameString = (string)currentTimeline.GetValue(TargetNameProperty);
        if( nameString != null )
        {
            if( nameScope is Style )
            {
                // We are inside a Style - we don't let people target anything.
                //  They're only allowed to modify the Styled object, which is
                //  already the implicit target.
                throw new InvalidOperationException(SR.Format(SR.Storyboard_TargetNameNotAllowedInStyle, nameString));
            }
            currentObjectName = nameString;
        }

        // The TargetProperty trumps the TargetName property.
        DependencyObject localTargetObject = (DependencyObject) currentTimeline.GetValue(TargetProperty);
        if( localTargetObject != null )
        {
            targetObject = localTargetObject;
            currentObjectName = null;
        }

        PropertyPath propertyPath = (PropertyPath)currentTimeline.GetValue(TargetPropertyProperty);
        if( propertyPath != null )
        {
            currentPropertyPath = propertyPath;
        }

View on GitHub (pinned to 81131a70a4)