dotnet/wpf · error · ElementNotAvailableException
ERROR_INVALID_MENU_HANDLE..ERROR_WINDOW_OF_OTHER_THREAD (1401-1408)
ERROR_INVALID_MENU_HANDLE..ERROR_WINDOW_OF_OTHER_THREAD (1401-1408)
Error message
ElementNotAvailableException
What it means
Misc's Win32 error-code mapper throws ElementNotAvailableException for system error codes 1400-1408, including ERROR_INVALID_MENU_HANDLE (1401) through ERROR_WINDOW_OF_OTHER_THREAD (1408). These codes indicate the window/menu/hook resource the call targeted is invalid or belongs to another thread, so the corresponding UIA element is treated as no longer available.
Solutions
- Re-acquire the element/handle — the underlying Win32 resource has gone stale
- Ensure UIA calls to another app's windows go through the proper cross-process automation path, not raw handles
- Catch ElementNotAvailableException around pattern/property calls and re-walk the tree
- Check that menus/popups are still open before querying their handles
Example fix
// before
var className = Misc.RealGetWindowClass(hwnd); // throws on 1401-1408
// after
try
{
var className = Misc.RealGetWindowClass(hwnd);
}
catch (ElementNotAvailableException)
{
// invalid menu/window handle or other-thread window: re-acquire element
hwnd = RefreshHandle();
} Defensive patterns
Strategy: try-catch
Validate before calling
// Invalidate stale handles before use:
if (!IsWindow(hwnd) || !IsMenu(hMenu)) { ReacquireHandles(); } Try / catch
try { QueryWindow(hwnd); } catch (ElementNotAvailableException) { ReacquireHandles(); Retry(); } Prevention
- Re-fetch menu/hook/window handles after every UI state change
- Avoid raw cross-thread window manipulation; use the automation API
- Log the exact Win32 error code to distinguish 1400-1408 variants
- Verify popup/menu windows still exist before querying them
When it happens
Trigger: A Win32 call made by the proxy fails with GetLastError in the 1400-1408 range — invalid window handles, invalid menu handles (1401), or a window owned by another thread (1408), typically during RealGetWindowClass, menu queries, or cross-thread window operations.
Common situations: Menu handles going stale after a menu closed; cross-thread access to windows of a UI thread that is busy or gone; x64-specific behavior seen with RealGetWindowClass.
Understand the failure class
Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.
Related errors
- ERROR_INVALID_PARAMETER (87)
- ERROR_NOACCESS (998) / ERROR_ACCESS_DENIED (5)
- ERROR_NOT_ENOUGH_MEMORY (8) / ERROR_OUTOFMEMORY (14)
- ERROR_SEM_TIMEOUT (121) / WAIT_TIMEOUT (258) / ERROR_SERVICE_REQUEST_TIMEOUT (1053) / ERROR_TIMEOUT (1460)
- ArgumentOutOfRangeException
AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14).
Data as JSON: /api/errors/c312dc2987b9b2a2.
Report an issue: GitHub.
Appendix: source
Thrown at src/Microsoft.DotNet.Wpf/src/UIAutomation/UIAutomationClientSideProviders/MS/Internal/AutomationProxies/Misc.cs:1682
internal static void ThrowWin32ExceptionsIfError(int errorCode)
{
switch (errorCode)
{
case 0: // 0 ERROR_SUCCESS The operation completed successfully.
// The error code indicates that there is no error, so do not throw an exception.
break;
case 6: // 6 ERROR_INVALID_HANDLE The handle is invalid.
case 1400: // 1400 ERROR_INVALID_WINDOW_HANDLE Invalid window handle.
case 1401: // 1401 ERROR_INVALID_MENU_HANDLE Invalid menu handle.
case 1402: // 1402 ERROR_INVALID_CURSOR_HANDLE Invalid cursor handle.
case 1403: // 1403 ERROR_INVALID_ACCEL_HANDLE Invalid accelerator table handle.
case 1404: // 1404 ERROR_INVALID_HOOK_HANDLE Invalid hook handle.
case 1405: // 1405 ERROR_INVALID_DWP_HANDLE Invalid handle to a multiple-window position structure.
case 1406: // 1406 ERROR_TLW_WITH_WSCHILD Cannot create a top-level child window.
case 1407: // 1407 ERROR_CANNOT_FIND_WND_CLASS Cannot find window class.
case 1408: // 1408 ERROR_WINDOW_OF_OTHER_THREAD Invalid window; it belongs to other thread.
throw new ElementNotAvailableException();
// We're getting this in AMD64 when calling RealGetWindowClass; adding this code
// to allow the DRTs to pass while we continue investigation.
case 87: // 87 ERROR_INVALID_PARAMETER
throw new ElementNotAvailableException();
case 8: // 8 ERROR_NOT_ENOUGH_MEMORY Not enough storage is available to process this command.
case 14: // 14 ERROR_OUTOFMEMORY Not enough storage is available to complete this operation.
throw new OutOfMemoryException();
case 998: // 998 ERROR_NOACCESS Invalid access to memory location.
case 5: // 5 ERROR_ACCESS_DENIED
throw new InvalidOperationException();
case 121: // 121 ERROR_SEM_TIMEOUT The semaphore timeout period has expired.
case 258: // 258 WAIT_TIMEOUT The wait operation timed out.
case 1053: // 1053 ERROR_SERVICE_REQUEST_TIMEOUT The service did not respond to the start or control request in a timely fashion.
case 1460: // 1460 ERROR_TIMEOUT This operation returned because the timeout period expired.View on GitHub (pinned to 81131a70a4)