dotnet/wpf · error · InvalidOperationException
SR.CyclicThemeStyleReferenceDetected
Error message
SR.CyclicThemeStyleReferenceDetected
What it means
A FrameworkElement's theme style resolution detected a reference cycle: while applying its theme style, the element (indirectly) triggers applying the same theme style again via its BasedOn chain or default style key. WPF guards this recursion with IsThemeStyleUpdateInProgress and throws InvalidOperationException to prevent infinite recursion. It almost always indicates a style with a BasedOn chain that loops back to itself.
Solutions
- Inspect the theme style's BasedOn chain for the element type and break the self/circular reference.
- Ensure DefaultStyleKey returns a distinct type whose style does not BasedOn the original element's style.
- Check generic.xaml / theme resource dictionaries for duplicated or recursive style keys after a rename/refactor.
Example fix
// before
<Style TargetType="local:MyControl" BasedOn="{StaticResource {x:Type local:MyControl}}" />
// after
<Style TargetType="local:MyControl" BasedOn="{StaticResource {x:Type Control}}" /> Defensive patterns
Strategy: validation
Validate before calling
var style = Application.Current.TryFindResource(myControl.DefaultStyleKey) as Style;
for (var s = style; s != null; s = s.BasedOn)
if (ReferenceEquals(s, style) && !ReferenceEquals(s, style)) continue; // walk chain
// Walk with a HashSet<Style> and throw if a style repeats before applying theme styles. Type guard
static bool HasStyleCycle(Style style) { var seen = new HashSet<Style>(); for (var s = style; s != null; s = s.BasedOn) { if (!seen.Add(s)) return true; } return false; } Try / catch
try { element.ApplyTemplate(); } catch (InvalidOperationException ex) when (ex.Message.Contains("cyclic") || ex.Message.Contains(themeStyleKey.ToString())) { log.Error("Cyclic theme style for " + element.GetType(), ex); } Prevention
- Never set a style BasedOn a style keyed to the same TargetType unless the base key differs.
- After renaming resource keys in generic.xaml, search for BasedOn references to the old key.
- Unit-test custom controls by instantiating them and calling ApplyTemplate in a test harness.
When it happens
Trigger: Calling ApplyThemeStyle/UpdateThemeStyle on an element whose theme style's BasedOn chain forms a cycle (e.g. a style BasedOn itself, or A BasedOn B BasedOn A), typically set via DefaultStyleKey or ThemeStyle lookup.
Common situations: Custom control authors declaring a style whose BasedOn points to a style keyed to the same type; refactoring generic.xaml resource keys so a style ends up BasedOn itself; overriding metadata DefaultStyleKeyProperty to a type whose style chains back.
Related errors
- SR.Format(SR.EventTriggerOnStyleNotAllowedToHaveTarget…
- SR.StylePropertyInStyleNotAllowed
- Animation_ChildMustBeKeyFrame
- Animation_ChildMustBeKeyFrame
- Animation_NoTextChildren
AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14).
Data as JSON: /api/errors/f36f6b512ebc8a62.
Report an issue: GitHub.
Appendix: source
Thrown at src/Microsoft.DotNet.Wpf/src/WpfGfx/codegen/mcg/generators/FrameworkElementTemplate.cs:761
if (toolTip != null)
{
FrameworkObject toolTipFO = new FrameworkObject(toolTip);
if (toolTipFO.IsValid)
{
TreeWalkHelper.InvalidateOnResourcesChange(toolTipFO.FE, toolTipFO.FCE, ResourcesChangeInfo.ThemeChangeInfo);
}
}
OnThemeChanged();
}
finally
{
IsThemeStyleUpdateInProgress = false;
}
}
else
{
throw new InvalidOperationException(SR.Format(SR.CyclicThemeStyleReferenceDetected, this));
}
}
// Called when the theme changes so resources not in the tree can be updated by subclasses
internal virtual void OnThemeChanged()
{
}
///<summary>
/// Initiate the processing for Loaded event broadcast starting at this node
/// </summary>
/// <remarks>
/// This method is to allow firing Loaded event from a Helper class since the override is protected
/// </remarks>
internal void FireLoadedOnDescendentsInternal()
{
// This is to prevent duplicate Broadcasts for the Loaded event
if (LoadedPending == null)View on GitHub (pinned to 81131a70a4)