{"record":{"id":"f36f6b512ebc8a62","repo":"dotnet/wpf","slug":"sr-cyclicthemestylereferencedetected","errorCode":null,"errorMessage":"SR.CyclicThemeStyleReferenceDetected","messagePattern":"SR\\.CyclicThemeStyleReferenceDetected","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/Microsoft.DotNet.Wpf/src/WpfGfx/codegen/mcg/generators/FrameworkElementTemplate.cs","lineNumber":761,"sourceCode":"                                                if (toolTip != null)\n                                                {\n                                                    FrameworkObject toolTipFO = new FrameworkObject(toolTip);\n                                                    if (toolTipFO.IsValid)\n                                                    {\n                                                        TreeWalkHelper.InvalidateOnResourcesChange(toolTipFO.FE, toolTipFO.FCE, ResourcesChangeInfo.ThemeChangeInfo);\n                                                    }\n                                                }\n\n                                                OnThemeChanged();\n                                            }\n                                            finally\n                                            {\n                                                IsThemeStyleUpdateInProgress = false;\n                                            }\n                                        }\n                                        else\n                                        {\n                                            throw new InvalidOperationException(SR.Format(SR.CyclicThemeStyleReferenceDetected, this));\n                                        }\n                                    }\n\n                                    // Called when the theme changes so resources not in the tree can be updated by subclasses\n                                    internal virtual void OnThemeChanged()\n                                    {\n                                    }\n\n                                    ///<summary>\n                                    ///     Initiate the processing for Loaded event broadcast starting at this node\n                                    /// </summary>\n                                    /// <remarks>\n                                    ///     This method is to allow firing Loaded event from a Helper class since the override is protected\n                                    /// </remarks>\n                                    internal void FireLoadedOnDescendentsInternal()\n                                    {\n                                        // This is to prevent duplicate Broadcasts for the Loaded event\n                                        if (LoadedPending == null)","sourceCodeStart":743,"sourceCodeEnd":779,"githubUrl":"https://github.com/dotnet/wpf/blob/81131a70a4c573cd62748a5c36908fc4d662daa9/src/Microsoft.DotNet.Wpf/src/WpfGfx/codegen/mcg/generators/FrameworkElementTemplate.cs#L743-L779","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\n<Style TargetType=\"local:MyControl\" BasedOn=\"{StaticResource {x:Type local:MyControl}}\" />\n// after\n<Style TargetType=\"local:MyControl\" BasedOn=\"{StaticResource {x:Type Control}}\" />","handlingStrategy":"validation","validationCode":"var style = Application.Current.TryFindResource(myControl.DefaultStyleKey) as Style;\nfor (var s = style; s != null; s = s.BasedOn)\n    if (ReferenceEquals(s, style) && !ReferenceEquals(s, style)) continue; // walk chain\n// Walk with a HashSet<Style> and throw if a style repeats before applying theme styles.","typeGuard":"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; }","tryCatchPattern":"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); }","preventionTips":["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."],"tags":["wpf","styles","recursion","xaml"],"backgroundTag":"cyclic-reference-detected","analyzedSha":"81131a70a4c573cd62748a5c36908fc4d662daa9","analyzedAt":"2026-09-14T10:12:48.479Z","contentChangedAt":"2026-09-14T10:12:48.479Z","schemaVersion":2},"datasetVersion":"2026-09-21T21:30:21.729Z"}