dotnet/wpf · error · InvalidOperationException
SR.ElementMustBeInPopup
Error message
SR.ElementMustBeInPopup
What it means
A ToolTip must be rooted inside a Popup. When the ToolTip's visual parent changes (OnVisualParentChanged) and Popup.IsRootedInPopup determines the tooltip is not properly hosted in a Popup, an InvalidOperationException is thrown. ToolTips rely on Popup infrastructure for positioning and display, so attaching one directly into the visual tree elsewhere is invalid.
Solutions
- Set the tooltip via element.ToolTip = toolTip instead of adding it as a child.
- Host the ToolTip in a Popup via Popup.Child if you need manual control.
- Remove code that re-parents the ToolTip; use ToolTipService attached properties for customization.
Example fix
// before stackPanel.Children.Add(myToolTip); // after button.ToolTip = myToolTip;
Defensive patterns
Strategy: validation
Validate before calling
if (element.ToolTip is ToolTip tt)
{
// do not add tt to a visual tree; assign via .ToolTip instead
}
element.ToolTip = myToolTip; Type guard
static bool IsPopupRooted(ToolTip tt) => tt.TemplatedParent is Popup || tt.Parent is Popup || tt.TemplatedParent != null && tt.TemplatedParent is Popup;
Try / catch
try { panel.Children.Add(control); }
catch (InvalidOperationException ex) when (ex.Message.Contains("ToolTip")) { /* assign via control.ToolTip instead */ } Prevention
- Never add a ToolTip as a child of a layout panel.
- Always assign ToolTips via the FrameworkElement.ToolTip property or ToolTipService.
- Create a new ToolTip per element instead of reparenting.
When it happens
Trigger: Assigning a ToolTip instance as a direct child of a panel/control (e.g. somePanel.Children.Add(toolTip)), or otherwise re-parenting a ToolTip outside a Popup, which fires OnVisualParentChanged.
Common situations: Confusing ToolTip with a normal control and adding it to a layout; programmatically building tooltips and inserting them into the tree instead of setting the FrameworkElement.ToolTip property.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- SR.CannotBeInsidePopup
- ' ' must be the root element of a tree, but has a logical…
- Animation_Invalid_DefaultValue
- By default, ToolTip property does not support ToolTip…
- Cannot remove signature from read-only file.
AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14).
Data as JSON: /api/errors/04fd223777266ba9.
Report an issue: GitHub.
Appendix: source
Thrown at src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Controls/ToolTip.cs:455
/// <summary>
/// Creates AutomationPeer (<see cref="UIElement.OnCreateAutomationPeer"/>)
/// </summary>
protected override AutomationPeer OnCreateAutomationPeer()
{
return new ToolTipAutomationPeer(this);
}
/// <summary>
/// Called when this element's visual parent changes
/// </summary>
/// <param name="oldParent"></param>
protected internal override void OnVisualParentChanged(DependencyObject oldParent)
{
base.OnVisualParentChanged(oldParent);
if (!Popup.IsRootedInPopup(_parentPopup, this))
{
throw new InvalidOperationException(SR.Format(SR.ElementMustBeInPopup, "ToolTip"));
}
}
internal override void OnAncestorChanged()
{
base.OnAncestorChanged();
if (!Popup.IsRootedInPopup(_parentPopup, this))
{
throw new InvalidOperationException(SR.Format(SR.ElementMustBeInPopup, "ToolTip"));
}
}
#endregion
#region Private Methods
protected override void OnContentChanged(object oldContent, object newContent)View on GitHub (pinned to 81131a70a4)