dotnet/wpf · error · InvalidOperationException
SR.HasLogicalParent
Error message
SR.HasLogicalParent
What it means
A logical element can have only one logical parent. In the ChangeLogicalParent path, if the element already has a parent (_parent) and a different newParent is supplied, it throws InvalidOperationException(SR.HasLogicalParent) to prevent 'logical child stealing' (see bug 970706) and corrupt trees.
Solutions
- Remove the child from its current logical parent before attaching to the new one
- Clear the old parent: oldParent.RemoveLogicalChild(child) then newParent.AddLogicalChild(child)
- Create a new instance for the second parent instead of sharing one element
Example fix
// before panelB.Children.Add(sharedChild); // sharedChild.Parent == panelA // after panelA.Children.Remove(sharedChild); panelB.Children.Add(sharedChild);
Defensive patterns
Strategy: validation
Validate before calling
if (child.Parent != null && !ReferenceEquals(child.Parent, newParent)) throw new InvalidOperationException("Child already has a different logical parent; detach first."); Type guard
bool IsReparentSafe(System.Windows.DependencyObject child, object newParent) => child.Parent == null || ReferenceEquals(child.Parent, newParent);
Try / catch
try { newParent.AddLogicalChild(child); } catch (InvalidOperationException ex) when (ex.Message.Contains("logical parent")) { ((FrameworkElement)child.Parent)?.RemoveLogicalChild(child); newParent.AddLogicalChild(child); } Prevention
- Always remove a child from its current parent before re-adding
- Never share a single UIElement instance between two containers
- Wrap reparenting in a MoveChild helper that detaches first
When it happens
Trigger: Calling ChangeLogicalParent(newParent) — or APIs that set Parent — on an element that already belongs to a different logical parent, without detaching first.
Common situations: Moving a UIElement from one container to another without removing it first; adding the same shared resource/child instance to two panels; re-parenting content items in a custom control.
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.HasLogicalParent
- SR.CannotBeSelfParent
- SR.CannotBeSelfParent
- SR.CannotBeSelfParent
- SR.CannotModifyLogicalChildrenDuringTreeWalk
AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14).
Data as JSON: /api/errors/6df7cb7dd9529aa9.
Report an issue: GitHub.
Appendix: source
Thrown at src/Microsoft.DotNet.Wpf/src/WpfGfx/codegen/mcg/generators/FrameworkElementTemplate.cs:364
///////////////////
//
// -- Approved By The Core Team --
//
// Do not allow foreign threads to change the tree.
// (This is a noop if this object is not assigned to a Dispatcher.)
//
// We also need to ensure that the tree is homogenous with respect
// to the dispatchers that the elements belong to.
//
this.VerifyAccess();
newParent?.VerifyAccess();
// Logical Parent must first be dropped before you are attached to a newParent
// This mitigates illegal tree state caused by logical child stealing as illustrated in bug 970706
if (_parent != null && newParent != null && _parent != newParent)
{
throw new System.InvalidOperationException(SR.HasLogicalParent);
}
// Trivial check to avoid loops
if (newParent == this)
{
throw new System.InvalidOperationException(SR.CannotBeSelfParent);
}
// invalid during a VisualTreeChanged event
VisualDiagnostics.VerifyVisualTreeChange(this);
// Logical Parent implies no InheritanceContext
if (newParent != null)
{
ClearInheritanceContext();
}
IsParentAnFE = newParent is FrameworkElement;View on GitHub (pinned to 81131a70a4)