dotnet/wpf · error · ArgumentException

SR.CircularOwnerChild

Error message

SR.CircularOwnerChild

What it means

Window.Owner setter throws ArgumentException when the new owner is one of the windows this window currently owns (a child in OwnedWindows). Making a window's own child its owner would create a circular owner/owned relationship, which WPF forbids. The message includes both window instances.

Solutions

  1. Choose a third window (or null) as the mutual owner instead of reversing the relationship.
  2. Clear the existing relationship first (set the child's Owner to null) before re-parenting.
  3. Guard the assignment with a check that value is not in this.OwnedWindows.

Example fix

// before
childA.Owner = mainWindow;
mainWindow.Owner = childA; // circular
// after
childA.Owner = mainWindow; // keep one-directional ownership
Defensive patterns

Strategy: validation

Validate before calling

bool isNotOwnedChild(Window self, Window candidate) => candidate == null || !self.OwnedWindows.OfType<Window>().Contains(candidate);

Try / catch

try { w.Owner = candidate; }
catch (ArgumentException) { candidate.Owner = null; w.Owner = candidate; }

Prevention

When it happens

Trigger: Setting A.Owner = B when B is already owned by A (A owns B, then B tries to own A), detected by scanning OwnedWindows for the value.

Common situations: Swapping owner/owned relationships dynamically; accidentally assigning the same window reference incorrectly in factory code that wires up many windows.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14). Data as JSON: /api/errors/d45682deccf7e02a. Report an issue: GitHub.

Appendix: source

Thrown at src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Window.cs:1262

                }

                if ( _ownerWindow == value )
                {
                    return;
                }

                if (!_disposed)
                {
                    // Check to see if value is already a child of this window.
                    // If yes, throw Exception
                    if (value != null)
                    {
                        WindowCollection ownedWindows = OwnedWindows;
                        for (int i = 0; i < ownedWindows.Count; i++)
                        {
                            if (ownedWindows[i] == value)
                            {
                                throw new ArgumentException(SR.Format(SR.CircularOwnerChild, value, this));
                            }
                        }
                    }

                    // Update OwnerWindows of the previous owner
                    // using OwnedWindowsInternl b/c we want to modifying the
                    // underlying collection
                    _ownerWindow?.OwnedWindowsInternal.Remove(this);
                }

                // Update parent handle. If value is null, then make parent
                // handle IntPtr.Zero
                _ownerWindow = value;

                // We should not do anything if the window is already closed and maybe throw exception.
                // In Dev10, it is unknown whether we can begin to throw exceptions, because it is a BC.
                // In Dev10, we still update _ownerWindow after window is closed just so that the Owner getter
                // returns the right value.

View on GitHub (pinned to 81131a70a4)