wailsapp/wails · error

GetClientRect(%d) failed

Error message

GetClientRect(%d) failed

What it means

GetClientRect returned FALSE, so the wrapper panics. The Win32 API fails when the given HWND is not a valid window — destroyed, not yet fully created, belongs to another process, or is a garbage handle. The panic message includes the numeric HWND to identify which handle failed.

Source

Thrown at v3/pkg/w32/user32.go:766

}

func InvalidateRect(hwnd HWND, rect *RECT, erase bool) bool {
	ret, _, _ := procInvalidateRect.Call(
		uintptr(hwnd),
		uintptr(unsafe.Pointer(rect)),
		uintptr(BoolToBOOL(erase)))

	return ret != 0
}

func GetClientRect(hwnd HWND) *RECT {
	var rect RECT
	ret, _, _ := procGetClientRect.Call(
		uintptr(hwnd),
		uintptr(unsafe.Pointer(&rect)))

	if ret == 0 {
		panic(fmt.Sprintf("GetClientRect(%d) failed", hwnd))
	}

	return &rect
}

func GetDC(hwnd HWND) HDC {
	ret, _, _ := procGetDC.Call(
		uintptr(hwnd))

	return HDC(ret)
}

func ReleaseDC(hwnd HWND, hDC HDC) bool {
	ret, _, _ := procReleaseDC.Call(
		uintptr(hwnd),
		uintptr(hDC))

	return ret != 0

View on GitHub (pinned to 0e754b1b40)

Solutions

  1. Guard the call with w32.IsWindow(hwnd) (or check hwnd != 0) before measuring
  2. Stop layout/resize goroutines when the window-destroyed event arrives, before the HWND becomes invalid
  3. Re-fetch HWNDs from the live window object instead of caching them across lifecycle events
  4. Recover in UI helpers so a shutdown race degrades to a skipped layout pass

Example fix

// before
rect := w32.GetClientRect(hwnd) // panics during teardown

// after
if hwnd == 0 || !w32.IsWindow(hwnd) {
    return // window destroyed; skip measurement
}
rect := w32.GetClientRect(hwnd)
Defensive patterns

Strategy: validation

Validate before calling

if hwnd == 0 || !w32.IsWindow(hwnd) {
    return nil, errors.New("GetClientRect: invalid window handle")
}
rect := w32.GetClientRect(hwnd)

Try / catch

defer func() {
    if r := recover(); r != nil {
        rect = nil // window died mid-measurement; skip this pass
    }
}()

Prevention

When it happens

Trigger: Calling GetClientRect on a window after WM_DESTROY/CloseHandle; using an HWND captured before window creation completed; passing 0 or an HWND from a different thread's window during teardown; calling after the native window was destroyed because the browser process crashed.

Common situations: Wails v3 Windows window-events code reading the client rect during shutdown or in a resize callback racing destruction; retry/recreate-window logic that keeps stale HWNDs; dialogs whose owner window was closed by the user.

Related errors


AI-assisted analysis of wailsapp/wails@0e754b1b40 (2026-08-15). Data as JSON: /api/errors/c69835eb5d9f5274. Report an issue: GitHub.