dotnet/wpf · error · InvalidOperationException

SR.CyclicStyleReferenceDetected

Error message

SR.CyclicStyleReferenceDetected

What it means

While a style is being applied, FrameworkElement checks that the incoming style does not create a reference cycle (e.g. a style whose BasedOn chain or resource lookup loops back to the element itself). If a cycle is detected during the style update, it throws InvalidOperationException(SR.CyclicStyleReferenceDetected) with the element in the message.

Solutions

  1. Break the BasedOn/resource cycle: make the style chain acyclic and remove self-referencing resource keys
  2. Use {DynamicResource} indirection carefully so the target style is not itself re-entered during update
  3. Rename conflicting resource keys so the lookup does not resolve back to the same style/element

Example fix

<!-- before: self-referencing BasedOn -->
<Style x:Key="s" TargetType="Button" BasedOn="{StaticResource s}"/>
<!-- after: base style separate from derived -->
<Style x:Key="base" TargetType="Button"/>
<Style x:Key="s" TargetType="Button" BasedOn="{StaticResource base}"/>
Defensive patterns

Strategy: validation

Validate before calling

// Walk the BasedOn chain and reject cycles before assigning
Style s = candidate; var seen = new HashSet<Style>();
while (s != null) { if (!seen.Add(s)) throw new InvalidOperationException("Cyclic style reference detected."); s = s.BasedOn; }

Type guard

bool IsAcyclicStyle(Style style) { var seen = new HashSet<Style>(); for (var s = style; s != null; s = s.BasedOn) if (!seen.Add(s)) return false; return true; }

Try / catch

try { el.Style = candidate; } catch (InvalidOperationException ex) when (ex.Message.Contains("cyclic")) { /* inspect and repair the BasedOn/resource chain */ }

Prevention

When it happens

Trigger: Setting FrameworkElement.Style to a Style that (transitively, via BasedOn or DynamicResource references) references the same element/style — detected because IsStyleUpdateInProgress is already true when the update re-enters.

Common situations: Style with BasedOn={StaticResource self-referencing key}; a control template setting its own Style; resource dictionaries with mutually referencing styles where the loop resolves back to the same element.

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/125c97723e2db590. Report an issue: GitHub.

Appendix: source

Thrown at src/Microsoft.DotNet.Wpf/src/WpfGfx/codegen/mcg/generators/FrameworkElementTemplate.cs:707

                                    {
                                        if (!HasStyleInvalidated)
                                        {
                                            if (IsStyleUpdateInProgress == false)
                                            {
                                                IsStyleUpdateInProgress = true;
                                                try
                                                {
                                                    InvalidateProperty(StyleProperty);
                                                    HasStyleInvalidated = true;
                                                }
                                                finally
                                                {
                                                    IsStyleUpdateInProgress = false;
                                                }
                                            }
                                            else
                                            {
                                                throw new InvalidOperationException(SR.Format(SR.CyclicStyleReferenceDetected, this));
                                            }
                                        }
                                    }

                                    /// <summary>
                                    ///     This method causes the ThemeStyleProperty to be re-evaluated
                                    /// </summary>
                                    internal void UpdateThemeStyleProperty()
                                    {
                                        if (IsThemeStyleUpdateInProgress == false)
                                        {
                                            IsThemeStyleUpdateInProgress = true;
                                            try
                                            {
                                                StyleHelper.GetThemeStyle([[instance.ThisString]]);

                                                // Update the ContextMenu and ToolTips separately because they aren't in the tree
                                                ContextMenu contextMenu =

View on GitHub (pinned to 81131a70a4)