dotnet/wpf · error · ElementNotAvailableException
ERROR_INVALID_PARAMETER (87)
ERROR_INVALID_PARAMETER (87)
Error message
ElementNotAvailableException
What it means
The same Win32 error mapper throws ElementNotAvailableException for ERROR_INVALID_PARAMETER (87). This case was added specifically because AMD64 systems returned error 87 from RealGetWindowClass for windows that are effectively unavailable, and the team decided to surface it as an unavailable element rather than a generic parameter failure.
Solutions
- Treat it as a stale/invalid element: re-acquire the HWND and retry once
- Skip elements whose handles yield error 87 during tree walks
- Catch ElementNotAvailableException and log the failing API plus error code for diagnosis
- Test on x64 — this mapping exists precisely for AMD64 RealGetWindowClass behavior
Example fix
// before
string cls = Misc.RealGetWindowClass(hwnd); // error 87 -> throw
// after
try
{
string cls = Misc.RealGetWindowClass(hwnd);
}
catch (ElementNotAvailableException)
{
// ERROR_INVALID_PARAMETER on x64: window considered invalid, skip element
cls = null;
} Defensive patterns
Strategy: fallback
Validate before calling
// Validate handle before RealGetWindowClass: if (!IsWindow(hwnd)) return null; // error 87 otherwise surfaces on x64
Try / catch
try { cls = RealGetWindowClass(hwnd); } catch (ElementNotAvailableException) { cls = FallbackClassName(hwnd); } Prevention
- Test automation on x64 where RealGetWindowClass reports error 87 more often
- Skip unverifiable elements during tree enumeration instead of failing the walk
- Keep an alternate identification path (class name from cached metadata)
- Treat error 87 on window APIs as 'unavailable element', not a code bug
When it happens
Trigger: A Win32 call in the proxy (notably RealGetWindowClass on AMD64) sets last error to 87 — the API was handed an HWND it considers invalid, often a partially torn-down or special window.
Common situations: 64-bit target processes with unusual/legacy windows; enumerating windows that disappear during enumeration; window classes of system-internal windows being queried.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- ERROR_INVALID_MENU_HANDLE..ERROR_WINDOW_OF_OTHER_THREAD (1401-1408)
- 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/a815615d157ca7f0.
Report an issue: GitHub.
Appendix: source
Thrown at src/Microsoft.DotNet.Wpf/src/UIAutomation/UIAutomationClientSideProviders/MS/Internal/AutomationProxies/Misc.cs:1687
// 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.
throw new TimeoutException();
default:
// Not sure how to map the reset of the error codes so throw generic Win32Exception.
throw new Win32Exception(errorCode);View on GitHub (pinned to 81131a70a4)