dotnet/wpf · warning · ElementNotAvailableException

ElementNotAvailableException

Error message

ElementNotAvailableException

What it means

GetParent on an MSAA-backed element is only valid below a window boundary; if the element's accessible role is Window, walking up would escape the automation 'window', so the provider throws ElementNotAvailableException. The UIA element has become invalid for navigation (its parent is out of scope).

Solutions

  1. Stop the upward walk when the element's CurrentControlType is Window/Pane or when AutomationElement.RootElement is reached
  2. Compare the element against AutomationElement.RootElement before requesting its parent
  3. Re-walk from RootElement using FindFirst/FindAll instead of walking up from a stale element
  4. Catch ElementNotAvailableException and treat it as 'reached the top of the scope' rather than a failure

Example fix

// before
while (e != null) { Process(e); e = walker.GetParent(e); }
// after
while (e != null && !Equals(e, AutomationElement.RootElement))
{
    if ((int)e.GetCurrentPropertyValue(AutomationElement.ControlTypeProperty)
        == ControlType.Window.Id) break; // window boundary: stop walking up
    Process(e);
    e = walker.GetParent(e);
}
Defensive patterns

Strategy: try-catch

Validate before calling

if (element == AutomationElement.RootElement || element.Current.ControlType == ControlType.Window) return null; // top of walk

Type guard

static bool IsWindowRoot(AutomationElement e) => e.Current.ControlType == ControlType.Window || e == AutomationElement.RootElement;

Try / catch

try { parent = walker.GetParent(element); }
catch (ElementNotAvailableException) { parent = null; /* reached window boundary */ }

Prevention

When it happens

Trigger: Calling TreeWalker.RawViewWalker/ControlViewWalker GetParent (or the Parent property) on an element whose accessible Role == AccessibleRole.Window — i.e. asking for the parent of a window root that is not the UIA root element.

Common situations: Walking up from a top-level window or dialog expecting to reach the desktop element; cached tree walks done after UI restructuring where the former child now behaves as a window root; custom proxies reporting Window role unexpectedly.

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

Appendix: source

Thrown at src/Microsoft.DotNet.Wpf/src/UIAutomation/UIAutomationClientSideProviders/MS/Internal/AutomationProxies/MSAANativeProvider.cs:1029

                    // note: _controlType can stay null. in that case we'll try to figure it out each time.
                    // if this is a performance problem we can add a separate boolean flag to indicate whether
                    // we have computed the control type.
                }

                // return the cached value
                return _controlType;
            }
        }

        private Accessible GetParent()
        {
            // this should never be called on a root.
            Debug.Assert(!IsRoot);

            // we should never step up out of a "window". we should hit the root first.
            if (_acc.Role == AccessibleRole.Window)
            {
                throw new ElementNotAvailableException();
            }

            Accessible parentAccessible = _acc.Parent;

            // if we get a null parent (Accessible.Parent will return null for IAccessible's
            // when we detect bad navigation) then we have no idea where we are. bail.
            if (parentAccessible == null)
            {
                throw new ElementNotAvailableException();
            }

            return parentAccessible;
        }


        // The following classes are known to have bad IAccessible implementation (eg.
        // overly complex structure or too many problems for the proxy to deal with).
        // Note that while similar "bad lists" are used by UIACore and the proxy manager,

View on GitHub (pinned to 81131a70a4)