dotnet/wpf · warning · ElementNotAvailableException

ElementNotAvailableException

Error message

ElementNotAvailableException

What it means

ElementUtil.Invoke marshals an automation peer call onto the peer's dispatcher thread. Before doing so it reads peer.Dispatcher; if the dispatcher is null the visual/HWND backing the peer is already disconnected, so any property or pattern call would be meaningless. The library throws ElementNotAvailableException to tell UIA clients the element has gone away.

Solutions

  1. Check the element still exists in the live UI tree before automating it (e.g. verify IsOffscreen/Hwnd source is non-null).
  2. Wrap the UIA client call in try/catch for ElementNotAvailableException and treat it as 'element gone', retrying with a fresh element reference.
  3. Re-query the element (FindFirst via the parent) instead of caching stale AutomationElement references across UI updates.
  4. In custom peer code, never hand out peers whose owner is disconnected; override and return null/false where the API allows.

Example fix

// before (client)
var valuePattern = (ValuePattern)element.GetCurrentPattern(ValuePattern.Pattern);
valuePattern.SetValue(text);
// after
if (element.Current.IsEnabled && !element.Current.IsOffscreen)
{
    try
    {
        var valuePattern = (ValuePattern)element.GetCurrentPattern(ValuePattern.Pattern);
        valuePattern.SetValue(text);
    }
    catch (ElementNotAvailableException)
    {
        element = parent.FindFirst(TreeScope.Children, condition); // refresh stale reference
    }
}
Defensive patterns

Strategy: try-catch

Validate before calling

if (element == null) throw new InvalidOperationException("element is stale");
// re-check freshness before use:
bool alive = element.Current.IsEnabled || !element.Current.IsOffscreen;

Type guard

bool IsElementAlive(AutomationElement e) => e != null && e.GetRuntimeId() != null;

Try / catch

try
{
    var value = element.GetCurrentPropertyValue(AutomationElement.NameProperty);
}
catch (ElementNotAvailableException)
{
    element = parent.FindFirst(TreeScope.Children, condition); // refresh and retry
}

Prevention

When it happens

Trigger: Calling any automation peer API (e.g. InvokePattern.Invoke, GetPropertyValue) routed through ElementUtil.Invoke when the peer's Dispatcher is null — typically because the underlying Visual/CoreDisconnected owner has been torn down or detached from the tree before the UIA call arrived.

Common situations: UI Automation clients (inspect.exe, screen readers, test frameworks) enumerate elements while the app closes a window or removes a control; a race where the element is destroyed between discovery and the follow-up call; accessing peers of controls on a closing page.

Related errors


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

Appendix: source

Thrown at src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Automation/ElementUtil.cs:182

        // Ensures that an element is enabled; throws exception otherwise
        internal static void CheckEnabled(Visual visual)
        {
            UIElement el = visual as UIElement;
            
            if( el != null && ! el.IsEnabled )
            {
                throw new ElementNotEnabledException();
            }
        }

        internal static object Invoke(AutomationPeer peer, DispatcherOperationCallback work, object arg)
        {
            Dispatcher dispatcher = peer.Dispatcher;

            // Null dispatcher likely means the visual is in bad shape!
            if( dispatcher == null )
            {
                throw new ElementNotAvailableException();
            }

            Exception remoteException = null;
            bool completed = false;

            object retVal = dispatcher.Invoke(            
                DispatcherPriority.Send,
                TimeSpan.FromMinutes(3),
                (DispatcherOperationCallback) delegate(object unused)
                {
                    try
                    {
                        return work(arg);
                    }
                    catch(Exception e)
                    {
                        remoteException = e;
                        return null;

View on GitHub (pinned to 81131a70a4)