dotnet/wpf · warning · ElementNotAvailableException

new ElementNotAvailableException(e)

Error message

new ElementNotAvailableException(e)

What it means

Inside HandleIAccessibleException, a COMException with E_OUTOFMEMORY (or equivalent) is deliberately translated to ElementNotAvailableException with the original as inner exception. OLEACC proxies report out-of-memory for non-critical reasons — notably the treeview proxy when the target HWND no longer exists and shared memory cannot be allocated in the target process — so the provider reinterprets it as 'element not available'.

Solutions

  1. Treat this as ElementNotAvailableException on the caller side: re-find the element and retry
  2. Detect and wait for target window recreation (e.g. re-find by WindowPattern / wait for WindowOpenedEvent) instead of using the stale reference
  3. Verify the target application/HWND is still alive (IsWindow / UIA not-visible check) before operating on proxied elements
  4. Batch reads with CacheRequest to minimize the number of cross-process proxy calls during unstable UI states

Example fix

// before
var item = FindTreeItem();
item.Select(); // may throw ElementNotAvailable (OOM proxy) after tree rebuild
// after
var item = WaitForElementByAutomationId(id, timeout: 5000);
if (item != null) item.Select();
Defensive patterns

Strategy: retry

Validate before calling

if (!IsWindowStillAlive(element)) return null; // e.g. compare RuntimeId / use WindowPattern
bool IsWindowStillAlive(AutomationElement e) {
    try { return !e.Current.IsOffscreen || e.Current.BoundingRectangle != Rect.Empty; }
    catch (ElementNotAvailableException) { return false; }
}

Type guard

static bool TryGet<T>(Func<T> f, out T value) {
    try { value = f(); return true; }
    catch (ElementNotAvailableException) { value = default; return false; }
}

Try / catch

for (int attempt = 0; attempt < 3; attempt++) {
    try { DoWork(element); break; }
    catch (ElementNotAvailableException ex)
        when (ex.InnerException is COMException ce && ce.HResult == unchecked((int)0x8007000E)) {
        element = FindElementAgain(); // OOM proxy => HWND likely gone; re-find
    }
}

Prevention

When it happens

Trigger: Calling into an IAccessible whose OLEACC proxy fails to allocate shared memory in the target process because GetWindowThreadProcessId fails — i.e. the target HWND died; any IAccessible call raising a COMException with OOM HRESULT, converted before the critical-exception check (OOM would otherwise be treated as critical).

Common situations: Treeview controls being destroyed/recreated while UIA enumerates their proxy; target window handle invalidated between discovery and call; memory pressure in the target process surfacing as OOM HRESULTs during cross-process MSAA calls.

Related errors


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

Appendix: source

Thrown at src/Microsoft.DotNet.Wpf/src/UIAutomation/UIAutomationClientSideProviders/MS/Internal/AutomationProxies/Accessible.cs:1293

            rect.right += rect.left;    // convert width to right
            rect.bottom += rect.top;    // convert height to bottom
            return rect;
        }
        
        // converts the exception into a more appropriate one and throws it,
        // or returns false indicating the caller should assume a default result
        // or returns true indicating the caller should rethrow the exception.
        private static bool HandleIAccessibleException(Exception e)
        {
            if (e is OutOfMemoryException)
            {
                // Some OLEACC proxies produce out-of-memory for non-critical reasons:
                // notably, the treeview proxy will raise this if the target HWND no longer exists,
                // GetWindowThreadProcessID fails and it therefore won't be able to allocate shared
                // memory in the target process, so it incorrectly assumes OOM.
                // (Need to check this before Misc.IsCriticalException, since it includes OOM as critical.)
                throw new ElementNotAvailableException(e);
            }

            if (e is NullReferenceException)
            {
                // Media Player and some other badly-implemented IAccessibles can return the correponding 
                // COM error code (E_POINTER).  This does not actually indicate a null dereference in this 
                // process.
                throw new ElementNotAvailableException(e);
            }

            if (Misc.IsCriticalException(e))
            {
                return true;
            }

            COMException comException = e as COMException;

            if (e is NotImplementedException)

View on GitHub (pinned to 81131a70a4)