{"record":{"id":"9a51d9bf05fc6660","repo":"dotnet/wpf","slug":"sr-reentrantvisualtreechangeerror","errorCode":null,"errorMessage":"SR.ReentrantVisualTreeChangeError","messagePattern":"SR\\.ReentrantVisualTreeChangeError","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Diagnostics/VisualDiagnostics.cs","lineNumber":213,"sourceCode":"\n        // detect whether a VisualTreeChanged event is in progress.  If so,\n        // throw an exception unless overridden by the app-context flag.\n        internal static void VerifyVisualTreeChange(DependencyObject d)\n        {\n            // write this so that the 90% case is inlined - check the flag and move on\n            if (s_HasVisualTreeChangedListeners)\n            {\n                VerifyVisualTreeChangeCore(d);\n            }\n        }\n\n        private static void VerifyVisualTreeChangeCore(DependencyObject d)\n        {\n            if (s_IsVisualTreeChangedInProgress)\n            {\n                if (!EnableHelper.AllowChangesDuringVisualTreeChanged(d))\n                {\n                    throw new InvalidOperationException(SR.Format(SR.ReentrantVisualTreeChangeError, nameof(VisualTreeChanged)));\n                }\n            }\n        }\n\n        internal static bool IsEnvironmentVariableSet(string value, string environmentVariable)\n        {\n            if (value != null)\n            {\n                return IsEnvironmentValueSet(value);\n            }\n\n            value = Environment.GetEnvironmentVariable(environmentVariable);\n\n            return IsEnvironmentValueSet(value);\n        }\n\n        internal static bool IsEnvironmentValueSet(string value)\n        {","sourceCodeStart":195,"sourceCodeEnd":231,"githubUrl":"https://github.com/dotnet/wpf/blob/81131a70a4c573cd62748a5c36908fc4d662daa9/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Diagnostics/VisualDiagnostics.cs#L195-L231","documentation":"VisualDiagnostics.VerifyVisualTreeChangeCore throws InvalidOperationException when code attempts to modify the visual tree while a VisualTreeChanged callback is in progress and the change is not explicitly allowed. Re-entrant mutation during change notification would produce inconsistent notifications and corrupt the diagnostic event stream, so WPF blocks it.","triggerScenarios":"Modifying the visual tree (adding/removing children, applying templates) inside a VisualTreeChanged event handler; changes triggered indirectly from the handler (e.g. setting a property that alters the tree).","commonSituations":"Debug/inspector tools that react to VisualTreeChanged by immediately editing the tree; property change handlers that add/remove elements while diagnostics are enabled (ENABLE_XAML_DIAGNOSTICS_SOURCE_INFO).","solutions":["Defer the mutation out of the callback: Dispatcher.BeginInvoke the tree change","Return from the handler before mutating; queue changes and apply after Changed completes","Call EnableHelper.AllowChangesDuringVisualTreeChanged if re-entrancy is intentional (diagnostics infrastructure only)","Disable VisualDiagnostics tooling in the affected path"],"exampleFix":"// before\nprivate void OnVisualTreeChanged(object sender, VisualTreeChangeEventArgs e)\n{\n    ((Panel)e.Parent).Children.Remove((UIElement)e.Child);\n}\n// after\nprivate void OnVisualTreeChanged(object sender, VisualTreeChangeEventArgs e)\n{\n    Dispatcher.BeginInvoke(() => ((Panel)e.Parent).Children.Remove((UIElement)e.Child));\n}","handlingStrategy":"try-catch","validationCode":"if (VisualDiagnostics.IsEnabled && isInsideVisualTreeChangedHandler)\n{\n    Dispatcher.BeginInvoke(() => ApplyTreeChange());\n}","typeGuard":"bool CanMutateTreeNow => !isInsideVisualTreeChangedHandler;","tryCatchPattern":"try { panel.Children.Add(child); }\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"VisualTreeChanged\"))\n{\n    Dispatcher.BeginInvoke(() => panel.Children.Add(child));\n}","preventionTips":["Never mutate the visual tree synchronously inside a VisualTreeChanged handler","Use Dispatcher.BeginInvoke to defer diagnostics-driven tree edits","Track whether a Changed callback is active with a flag in tooling code"],"tags":["wpf","invalidoperationexception","visual-tree","reentrancy"],"backgroundTag":"invalid-state-transition","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"}