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

  1. Treat it as a stale/invalid element: re-acquire the HWND and retry once
  2. Skip elements whose handles yield error 87 during tree walks
  3. Catch ElementNotAvailableException and log the failing API plus error code for diagnosis
  4. 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

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


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)