dotnet/wpf · error · ElementNotAvailableException

RPC_E_SERVERFAULT/RPC_E_DISCONNECTED/RPC_E_UNAVAILABLE/DISP_E_BADINDEX/E_INTERFACEUNKNOWN/E_UNKNOWNWORDERROR/RPC_E_SYS_CALL_FAILED

RPC_E_SERVERFAULT/RPC_E_DISCONNECTED/RPC_E_UNAVAILABLE/DISP_E_BADINDEX/E_INTERFACEUNKNOWN/E_UNKNOWNWORDERROR/RPC_E_SYS_CALL_FAILED

Error message

ElementNotAvailableException(e)

What it means

HandleIAccessibleException maps a specific set of RPC/DISPATCH COM error codes — RPC_E_SERVERFAULT, RPC_E_DISCONNECTED, RPC_E_UNAVAILABLE, DISP_E_BADINDEX, E_INTERFACEUNKNOWN, E_UNKNOWNWORDERROR, RPC_E_SYS_CALL_FAILED — to ElementNotAvailableException with the original exception attached. All of these mean the out-of-process accessibility server effectively disappeared or returned an unusable response, so the element is declared not available to UIA clients.

Solutions

  1. Catch ElementNotAvailableException and re-acquire the element by AutomationId/RuntimeId, then retry with bounded retries
  2. Detect target app exit (Process.HasExited / UIA WindowClosedEvent) before assuming the element should exist
  3. Use CacheRequest to fetch all needed properties in one call, shrinking the window for mid-call disconnections
  4. Slow down / debounce UIA queries against targets known to churn (Word documents, transient windows) and subscribe to structure-changed events instead of polling

Example fix

// before
var value = element.Current.Value; // throws if server disconnected mid-session
// after
string value;
try {
    value = element.Current.Value;
} catch (ElementNotAvailableException) when (RetryOnce()) {
    value = FindElement(id).Current.Value;
}
Defensive patterns

Strategy: retry

Validate before calling

// Verify the hosting process still exists before touching its elements
if (targetProcess == null || targetProcess.HasExited) return null;
// And verify the element still resolves:
var found = root.FindFirst(TreeScope.Descendants,
    new PropertyCondition(AutomationElement.AutomationIdProperty, id));
if (found == null) return null;

Type guard

static bool IsElementAlive(AutomationElement e) {
    try { var _ = e.GetRuntimeId(); return true; }
    catch (ElementNotAvailableException) { return false; }
}

Try / catch

const int MaxRetries = 3;
for (int i = 0; i < MaxRetries; i++) {
    try { result = element.Current.Value; break; }
    catch (ElementNotAvailableException ex)
        when (ex.InnerException is COMException ce &&
              (ce.HResult == unchecked((int)0x80010108) || // RPC_E_DISCONNECTED
               ce.HResult == unchecked((int)0x800706BA) || // RPC_E_SERVERFAULT-ish
               ce.HResult == unchecked((int)0x800706BE))) {
        element = FindElementAgain();
        if (element == null) throw; // target truly gone
    }
}

Prevention

When it happens

Trigger: Any IAccessible call whose server returns one of the listed HRESULTs: the MSAA/OLEACC server crashed (RPC_E_SERVERFAULT), disconnected (RPC_E_DISCONNECTED), vanished (RPC_E_UNAVAILABLE), children indices became stale (DISP_E_BADINDEX), interfaces changed (E_INTERFACEUNKNOWN), Word closed mid-search (E_UNKNOWNWORDERROR), or a system call failed during RPC (RPC_E_SYS_CALL_FAILED).

Common situations: Target application crashes or exits during automation; Office (Word) documents closing while UIA searches run; long-running automation sessions outliving the target UI; cross-process RPC to the accessibility server breaking during heavy UI churn; child collections shrinking between discovery and access.

Related errors


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

Appendix: source

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

                return false;
            }
            else if (comException != null)
            {
                // convert certain COM exceptions to ElementNotAvailable exceptions.
                // these occur when the underlying UI elements disappear but we are still
                // holding pointers to them, like when Trident navigates to a new page.
                int errorCode = comException.ErrorCode;

                switch (errorCode)
                {
                    case NativeMethods.RPC_E_SERVERFAULT: // The server threw an exception.
                    case NativeMethods.RPC_E_DISCONNECTED: // The object invoked has disconnected from its clients.
                    case NativeMethods.RPC_E_UNAVAILABLE: // The server has disappeared
                    case NativeMethods.DISP_E_BADINDEX: // Index out of Range (Usually means Children have disappeared)
                    case NativeMethods.E_INTERFACEUNKNOWN: // The interface is unknown, usually because things have changed.
                    case NativeMethods.E_UNKNOWNWORDERROR: // An unknown Error code thrown by Word being closed while a search is running
                    case NativeMethods.RPC_E_SYS_CALL_FAILED: // System call failed during RPC.
                        throw new ElementNotAvailableException(e);

                    case NativeMethods.E_FAIL:
                        // An unknown or generic error occurred; treat as a not-impl. (Other methods on the object
                        // may still work, so don't treat as ElementNotAvailable.)
                    case NativeMethods.E_MEMBERNOTFOUND:
                        // The object does not support the requested property or action. For example,
                        // a push button returns this value if you request its Value property, since
                        // it does not have a Value property.
                    case NativeMethods.E_NOTIMPL:
                        // just return on E_NOTIMPL errors
                        return false;

                    case NativeMethods.E_OUTOFMEMORY:
                        // 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.
                        throw new ElementNotAvailableException(e);

View on GitHub (pinned to 81131a70a4)