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

  1. Remove the child from its current logical parent before attaching to the new one
  2. Clear the old parent: oldParent.RemoveLogicalChild(child) then newParent.AddLogicalChild(child)
  3. 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

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


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)