dotnet/wpf · error · InvalidOperationException
SR.Format(SR.CyclicThemeStyleReferenceDetected, this)
Error message
SR.Format(SR.CyclicThemeStyleReferenceDetected, this)
What it means
FrameworkElement.UpdateThemeStyleProperty detects re-entrancy of the theme style update: it is invoked (via OnInitialized or OnResourcesChanged) while IsThemeStyleUpdateInProgress is already true, meaning the theme style resolution cycled back to the same element. WPF throws InvalidOperationException (CyclicThemeStyleReferenceDetected) to break the recursion.
Solutions
- Break the resource cycle: ensure the theme style's resource references do not point back to resources whose change re-invalidates the element's theme style.
- Defer resource/style changes in OnThemeChanged/OnResourcesChanged overrides with Dispatcher.BeginInvoke.
- Keep ThemeStyle/DefaultStyleKey metadata static; don't change theme-related keys during style application.
- The exception message names the offending element — inspect its theme style and referenced dictionaries.
Example fix
// before
protected override void OnThemeChanged()
{
SetResourceReference(StyleProperty, ThemeKey); // re-invalidates theme style mid-update
}
// after
protected override void OnThemeChanged()
{
Dispatcher.BeginInvoke(() => SetResourceReference(StyleProperty, ThemeKey));
} Defensive patterns
Strategy: validation
Validate before calling
if (element.IsThemeStyleUpdateInProgress)
throw new InvalidOperationException("Theme style update already in progress; defer resource changes."); Type guard
bool IsSafeForThemeStyleUpdate(FrameworkElement e) => !e.IsThemeStyleUpdateInProgress;
Try / catch
try
{
element.InvalidateProperty(ThemeStyleProperty);
}
catch (InvalidOperationException ex) when (ex.Message.Contains("cyclic"))
{
Log.Warn("Cyclic theme style reference detected.", ex);
} Prevention
- Avoid re-applying theme styles in OnThemeChanged/OnResourcesChanged overrides.
- Ensure theme dictionary resources do not reference back to the element's own theme style.
- Batch theme switches so resource dictionary changes don't invalidate styles mid-application.
When it happens
Trigger: Theme style lookup for the element triggers OnResourcesChanged or re-initialization on the same element before the current theme style update finishes — e.g. resource references inside the theme style that invalidate the element's theme style again, or overrides that re-fetch theme style during the update.
Common situations: Custom control theme dictionaries with DynamicResource keys that change during style application; overriding OnThemeChanged/OnResourcesChanged to re-apply the theme style; resource dictionary churn while a theme style is being applied (e.g. theme switch handlers).
Related errors
- SR.Format(SR.CyclicThemeStyleReferenceDetected, this)
- SR.CannotBeSelfParent
- SR.Format(SR.CyclicStyleReferenceDetected, this)
- Animation_Invalid_DefaultValue
- Cannot remove signature from read-only file.
AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14).
Data as JSON: /api/errors/d833129321e558eb.
Report an issue: GitHub.
Appendix: source
Thrown at src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Generated/FrameworkElement.cs:679
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)