dotnet/wpf · warning · System.Windows.Automation.ElementNotAvailableException

ElementNotAvailableException

Error message

ElementNotAvailableException

What it means

ElementNotAvailableException is the UI Automation proxy signal that the underlying Windows element has vanished or is no longer accessible. In WindowsMenu.GetHierarchyParent, the code asks the target hwnd for its menu handle (HmenuFromHwnd); when the OS returns IntPtr.Zero the menu no longer exists (the window was closed, destroyed, or never had a menu), so the proxy throws because it cannot compute a hierarchy parent for a dead element.

Solutions

  1. Re-fetch the element instead of using stale references: after any window close/menu rebuild, find the element again via AutomationElement.RootElement.FindFirst rather than walking from the old node.
  2. Wrap tree-walk calls (TreeWalker.GetParent/GetFirstChild) in try/catch for ElementNotAvailableException and treat the element as gone.
  3. Use FindAll/FindFirst with a TreeScope query instead of manual walker traversal; UIA core handles vanished elements more gracefully there.
  4. Ensure the automation target window is fully initialized and still alive before walking its menu (check AutomationElement.IsOffscreen / NativeWindowHandle and process HasExited).

Example fix

// before
AutomationElement parent = TreeWalker.ControlViewWalker.GetParent(menuElement);
// after
AutomationElement parent;
try
{
    parent = TreeWalker.ControlViewWalker.GetParent(menuElement);
}
catch (ElementNotAvailableException)
{
    parent = null; // window/menu closed; re-find element if needed
}
Defensive patterns

Strategy: try-catch

Validate before calling

// before walking, check element is still alive
if (menuElement == null || (bool)menuElement.GetCurrentPropertyValue(AutomationElement.IsOffscreenProperty))
    return null;
var hwnd = (IntPtr)menuElement.GetCurrentPropertyValue(AutomationElement.NativeWindowHandleProperty);
if (hwnd == IntPtr.Zero) return null;

Type guard

static bool IsAlive(AutomationElement el)
{
    try { var _ = el.Current.Name; return true; }
    catch (ElementNotAvailableException) { return false; }
}

Try / catch

try
{
    parent = TreeWalker.ControlViewWalker.GetParent(menuElement);
}
catch (ElementNotAvailableException)
{
    parent = null; // stale element; re-find via FindFirst if needed
}

Prevention

When it happens

Trigger: Calling AutomationElement.TreeWalker (RawViewWalker/ControlViewWalker) GetParent/GetFirstChild on a WindowsMenu proxy whose hwnd's menu handle has become zero — typically because the window's menu was destroyed or the window closed between the element being found and the parent being resolved. Reached via callers WindowsMenu, FixMDIMenuType, and MenuEvents during tree walks and MDI menu restructuring.

Common situations: UIA clients walking menus of apps being closed or resized; MDI applications whose menu bar is rebuilt/replaced while automation is traversing it; tests that hold AutomationElement references across window close; timing races where the element is cached after the native menu is gone.

Related errors


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

Appendix: source

Thrown at src/Microsoft.DotNet.Wpf/src/UIAutomation/UIAutomationClientSideProviders/MS/Internal/AutomationProxies/WindowsMenu.cs:535

            System.Diagnostics.Debug.WriteLine(sb.ToString());
#endif

            return result;
        }

        // Return menuItem object which is a hierarchical parent of the given menu (specified via hwnd)
        // return NULL in the case when menu does not have a parent (e.g. Context menu)
        // NOTE: this method should not be called for the menuItem that lives on the System or Menubar
        internal static MenuItem GetHierarchyParent(IntPtr hwnd)
        {
            int ownerMenuItemPos = -1;
            IntPtr menuParent = IntPtr.Zero;
            IntPtr hwndParent = IntPtr.Zero;

            IntPtr menu = HmenuFromHwnd(hwnd);
            if (menu == IntPtr.Zero)
            {
                throw new ElementNotAvailableException();
            }
            MenuType currentType = GetSubMenuType(hwnd, menu);
            MenuType parentType = MenuType.Toplevel;

            if (currentType == MenuType.Submenu)
            {
                if (!GetSubMenuParent(hwnd, out menuParent, out hwndParent, out ownerMenuItemPos, out parentType))
                {
                    return null;
                }

                ProxyFragment parent = null;
                if (parentType == MenuType.Toplevel)
                {
                    // Top Level Menu.
                    // We need to have the parenthood defined in the same way as if it was done
                    // from the non client area code.

View on GitHub (pinned to 81131a70a4)