dotnet/wpf · error · InvalidOperationException

SR.CannotBeSelfParent

Error message

SR.CannotBeSelfParent

What it means

ChangeLogicalParent also rejects self-parenting: if newParent == this, InvalidOperationException (CannotBeSelfParent) is thrown. Allowing an element to be its own logical parent would create a cycle, breaking tree invariants and infinite-walking the tree.

Solutions

  1. Verify the newParent argument is the intended ancestor, not the element itself.
  2. Break data cycles before they reach the visual/logical tree (e.g. detect recursion in your model).
  3. Add an assertion/guard in custom container code that child != this before attaching.

Example fix

// before
if (parent == null) parent = this; // wrong fallback
this.ChangeLogicalParent(parent);
// after
if (parent == null || parent == this)
    throw new ArgumentException("Invalid logical parent");
this.ChangeLogicalParent(parent);
Defensive patterns

Strategy: validation

Validate before calling

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

Type guard

static bool IsValidParent(DependencyObject self, DependencyObject candidate) => candidate != null && !ReferenceEquals(candidate, self);

Try / catch

try { element.ChangeLogicalParent(newParent); } catch (InvalidOperationException ex) when (ex.Message.Contains("self")) { Log("cycle detected"); }

Prevention

When it happens

Trigger: Calling ChangeLogicalParent with the element itself, or code paths (AddLogicalChild on self, self-referential binding/content assignment) that end up attaching an element as its own child/parent.

Common situations: Recursive data structures rendered directly into themselves; programming errors in custom containers where 'this' is passed instead of the intended child; cyclic content assignment in templates.

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

Appendix: source

Thrown at src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Generated/FrameworkContentElement.cs:306

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