dotnet/wpf · error · InvalidOperationException

SR.CannotBeSelfParent

Error message

SR.CannotBeSelfParent

What it means

ChangeLogicalParent includes a trivial loop check: an element cannot be its own parent. If newParent == this, it throws InvalidOperationException(SR.CannotBeSelfParent). This prevents infinite parent chains and illegal tree structure.

Solutions

  1. Verify the arguments before parenting: assert(child != parent)
  2. Skip the call when newParent == this (it is a no-op semantically)
  3. Trace the re-parenting code path for cycles where an ancestor is re-added as a descendant

Example fix

// before
child.ChangeLogicalParent(child);
// after
if (child != newParent) child.ChangeLogicalParent(newParent);
Defensive patterns

Strategy: validation

Validate before calling

if (ReferenceEquals(child, newParent)) throw new ArgumentException("An element cannot be its own logical parent.");

Type guard

bool IsNotSelfParent(System.Windows.FrameworkElement child, object newParent) => !ReferenceEquals(child, newParent);

Try / catch

try { child.ChangeLogicalParent(newParent); } catch (InvalidOperationException ex) when (ex.Message.Contains("own parent")) { /* skip; self-parenting is a no-op */ }

Prevention

When it happens

Trigger: Calling ChangeLogicalParent(element) on itself — e.g. accidentally passing 'this' instead of the intended child/parent in custom logical-tree code, or a cycle where a container ends up as its own child.

Common situations: Custom panel/content-control code wiring parents; recursion bugs where a node gets added to itself; generic re-parenting utilities mishandling self-references.

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/5cd1a21bfb617f03. Report an issue: GitHub.

Appendix: source

Thrown at src/Microsoft.DotNet.Wpf/src/WpfGfx/codegen/mcg/generators/FrameworkElementTemplate.cs:370

                                        // (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;

                                        DependencyObject oldParent = _parent;
                                        OnNewParent(newParent);

                                        // Update Has[Loaded/Unloaded]Handler Flags
                                        BroadcastEventHelper.AddOrRemoveHasLoadedChangeHandlerFlag(this, oldParent, newParent);

View on GitHub (pinned to 81131a70a4)