dotnet/wpf · warning · ElementNotAvailableException

Element no longer available.

Error message

Element no longer available.

What it means

ElementNotAvailableException ('Element no longer available.') is thrown by the WindowsButton proxy's RaiseEvents path when the underlying Win32 window handle (hwnd) is no longer a valid window (IsWindow returns false). UIA elements are proxies over live HWNDs; once the target window is destroyed, the proxy can no longer raise events on it. The library throws rather than silently dropping the event so clients know the element went stale.

Solutions

  1. Wrap event-handler bodies and any use of stale AutomationElement references in try-catch for ElementNotAvailableException and ignore the event.
  2. Re-resolve the element from the desktop via a fresh FindFirst/FindAll instead of reusing cached references across UI changes.
  3. Use AutomationElement caching (CacheRequest) with events and guard property reads so stale elements fail fast without cascading.
  4. Serialize UI interactions with the app's lifecycle so the client stops interacting before controls are disposed.

Example fix

// before
AutomationEventHandler handler = (src, e) =>
{
    var button = (WindowsButtonProxy)src;
    button.Invoke();
};
// after
AutomationEventHandler handler = (src, e) =>
{
    try
    {
        var button = (WindowsButtonProxy)src;
        button.Invoke();
    }
    catch (ElementNotAvailableException)
    {
        // element's window was destroyed; re-find it
        var fresh = desktop.FindFirst(TreeScope.Descendants, nameCondition);
        fresh?.Invoke();
    }
};
Defensive patterns

Strategy: try-catch

Validate before calling

// C# (UIA client)
// There is no public IsWindow check; guard by re-resolving the element
var fresh = AutomationElement.RootElement.FindFirst(TreeScope.Descendants,
    new PropertyCondition(AutomationElement.NameProperty, buttonName));
bool usable = fresh != null;

Type guard

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

Try / catch

try
{
    // interact with element / handle its event payload
}
catch (ElementNotAvailableException)
{
    // window destroyed; re-find or skip
}

Prevention

When it happens

Trigger: An event handler (AutomationEventHandler / property-changed / structure-changed callback) fires for a WindowsButton whose hwnd has been destroyed; RaiseEvents validates with UnsafeNativeMethods.IsWindow(hwnd) and throws ElementNotAvailableException on failure.

Common situations: Desktop apps closing dialogs or disposing controls while a UIA client holds cached references; race conditions where a button is removed or re-created between event registration and delivery; automated UI tests where the app under test crashes or exits mid-run.

Related errors


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

Appendix: source

Thrown at src/Microsoft.DotNet.Wpf/src/UIAutomation/UIAutomationClientSideProviders/MS/Internal/AutomationProxies/WindowsButton.cs:153

            catch (ElementNotAvailableException)
            {
                return null;
            }

            return new WindowsButton(hwnd, null, type, style, null);
        }

        // Static create method called by the event tracker system.
        // WinEvents are thrown only when a notification has been set for a
        // specific item. Create the item first and check for details afterward.
        internal static void RaiseEvents (IntPtr hwnd, int eventId, object idProp, int idObject, int idChild)
        {
            if (idObject != NativeMethods.OBJID_VSCROLL && idObject != NativeMethods.OBJID_HSCROLL)
            {
                // Can not RaiseEvents on windows that are no longer available.
                if (!UnsafeNativeMethods.IsWindow(hwnd))
                {
                    throw new ElementNotAvailableException();
                }

                WindowsButton wtv = (WindowsButton)Create(hwnd, 0);

                // Create can return null if we don't know what kind of button this is
                if (wtv == null)
                {
                    return;
                }
                
                //Only one event is generated for the winforms button so no need to check the pressed state.
                if (wtv._acc != null)
                {
                    if (idProp == SelectionItemPattern.ElementSelectedEvent)
                    {
                        if (!wtv._acc.HasState(AccessibleState.Checked))
                        {
                            eventId = NativeMethods.EventObjectSelectionRemove;

View on GitHub (pinned to 81131a70a4)