dotnet/wpf · error
' ' must be the root element of a tree, but has a logical…
Error message
'{0}' must be the root element of a tree, but has a logical parent '{1}'. What it means
Popup.CreateRootPopupInternal (used by ContextMenu, ToolTip, etc.) requires the popup's Child to be a root element: before attaching it, the child must have no existing logical parent. WPF throws InvalidOperationException because an element with a logical parent cannot be reparented into the popup's visual/logical tree.
Solutions
- Remove the child from its current logical parent first (e.g. remove it from the containing Panel or set the property holding it to null).
- Use a fresh instance for the popup instead of a shared element (e.g. create a new instance from the DataTemplate/Resource).
- If intentionally moving the element, disconnect it via LogicalTreeHelper / clear the parent property before assigning Child.
Example fix
// before
var panel = (StackPanel)FindResource("myPanel");
popup.Child = panel; // panel already parented
// after
popup.Child = new StackPanel { Children = { new TextBlock { Text = "hi" } } }; // fresh instance Defensive patterns
Strategy: validation
Validate before calling
if (LogicalTreeHelper.GetParent(child) != null || VisualTreeHelper.GetParent(child) != null)
throw new InvalidOperationException("Child must be a root element before assigning to Popup.Child"); Type guard
bool CanBePopupChild(UIElement child) =>
LogicalTreeHelper.GetParent(child) == null && VisualTreeHelper.GetParent(child) == null; Try / catch
try { popup.Child = element; }
catch (InvalidOperationException ex) { /* detach element or instantiate a new one */ } Prevention
- Never share one UIElement across two popups or between a window and a popup
- Instantiate fresh elements from templates/resources
- Detach from parent before reparenting
When it happens
Trigger: Setting popup.Child (or passing a child to CreateRootPopup) with an element that already has a logical parent, e.g. an element that is still in a Window/Page's logical tree, or reusing a shared resource element across two popups.
Common situations: Reusing the same UIElement instance for two popups; moving a control from a window into a popup without calling Detach/RemoveChild first; declaring a resource element and assigning it both in XAML and code.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- SR.CreateRootPopup_ChildHasVisualParent
- Cannot reopen a popup in the closed event handler.
- Microsoft.Windows.Controls.SR.ResizeParametersNotValid
- SR.CannotBeInsidePopup
- SR.CannotBeSelfParent
AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14).
Data as JSON: /api/errors/7a49134346ad7273.
Report an issue: GitHub.
Appendix: source
Thrown at src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Controls/Primitives/Popup.cs:890
/// <summary>
/// Internal implementation of CreateRootPopup to allow tooltips to
/// override the popup's placement in case the tooltip comes from keyboard focus.
/// </summary>
/// <param name="popup">The parent popup that the child will be hooked up to.</param>
/// <param name="child">The element to be the child of the popup.</param>
/// <param name="bindTreatMousePlacementAsBottomProperty">Whether to bind TreatMousePlacementAsBottomProperty to the child's FromKeyboard property</param>
internal static void CreateRootPopupInternal(Popup popup, UIElement child, bool bindTreatMousePlacementAsBottomProperty)
{
ArgumentNullException.ThrowIfNull(popup);
ArgumentNullException.ThrowIfNull(child);
Debug.Assert(!bindTreatMousePlacementAsBottomProperty || child is ToolTip, "child must be a Tooltip to bind TreatMousePlacementAsBottomProperty");
// When we get here, the Child must not have already been visually or logically parented.
object currentParent = null;
if ((currentParent = LogicalTreeHelper.GetParent(child)) != null)
{
throw new InvalidOperationException(SR.Format(SR.CreateRootPopup_ChildHasLogicalParent, child, currentParent));
}
if ((currentParent = VisualTreeHelper.GetParent(child)) != null)
{
throw new InvalidOperationException(SR.Format(SR.CreateRootPopup_ChildHasVisualParent, child, currentParent));
}
// PlacementTarget must be set before hooking up the child so that resource
// lookups can work. The Popup for tooltip and context menu isn't in the tree
// so FE relies on GetUIParentCore to return the placement target as the
// effective logical parent
Binding binding = new Binding("PlacementTarget")
{
Mode = BindingMode.OneWay,
Source = child
};
popup.SetBinding(PlacementTargetProperty, binding);
View on GitHub (pinned to 81131a70a4)