GraphiteEditor/Graphite · critical

CreateWindowExW failed

Error message

CreateWindowExW failed

What it means

Panic when the Win32 CreateWindowExW call returns a null HWND. In this code the window being created is the helper window used to subclass the main window (the main window's HWND is passed through WM_NCCREATE so the helper can store it). A null return means the OS refused window creation: the window class was not registered, invalid parameters, exhaustion of USER/GDI handles, or broken session state.

Source

Thrown at desktop/src/window/win/native_handle.rs:71

		let style = WS_POPUP;
		let helper = unsafe {
			CreateWindowExW(
				ex,
				PCWSTR(HELPER_CLASS_NAME.encode_utf16().collect::<Vec<_>>().as_ptr()),
				PCWSTR::null(),
				style,
				0,
				0,
				0,
				0,
				Some(main),
				None,
				None,
				// Pass the main window's HWND to WM_NCCREATE so the helper can store it.
				Some(&main as *const _ as _),
			)
		}
		.expect("CreateWindowExW failed");

		// Subclass the main window.
		// https://learn.microsoft.com/windows/win32/api/winuser/nf-winuser-setwindowlongptra
		let prev_window_message_handler = unsafe { SetWindowLongPtrW(main, GWLP_WNDPROC, main_window_handle_message as *const () as isize) };
		if prev_window_message_handler == 0 {
			let _ = unsafe { DestroyWindow(helper) };
			panic!("SetWindowLongPtrW failed");
		}

		let native_handle = NativeWindowHandle {
			main,
			helper,
			prev_window_message_handler,
			state: Arc::new(Mutex::new(NativeWindowState::default())),
		};
		registry::insert(&native_handle);

		// Place the helper over the main window and show it without activation.

View on GitHub (pinned to c507b35645)

Solutions

  1. Capture GetLastError at the failure site (or via a debugger) to get the exact Win32 error code (ERROR_CLASS_DOES_NOT_EXIST, ERROR_NOT_ENOUGH_MEMORY, etc.)
  2. Check handle usage in Task Manager (Details tab, add USER objects/GDI objects columns) and close leaking applications; reboot clears session handle leaks
  3. Verify the class registration code path always runs before CreateWindowExW for both main and helper windows
  4. Reconnect the RDP session or reboot if session state is suspected corrupt

Example fix

// before
}
.expect("CreateWindowExW failed");

// after
let hwnd = { /* CreateWindowExW(...) */ };
if hwnd.is_invalid() {
	let err = unsafe { GetLastError() };
	panic!("CreateWindowExW failed with Win32 error {err}");
}
Defensive patterns

Strategy: try-catch

Try / catch

let hwnd = unsafe { /* CreateWindowExW(...) */ };
if hwnd.is_invalid() {
	let code = unsafe { windows::Win32::Foundation::GetLastError() };
	panic!("CreateWindowExW failed with Win32 error {}", code.0);
}

Prevention

When it happens

Trigger: The window class for the helper window was never registered or registration failed silently earlier; USER/GDI handle exhaustion in the process or session (handle leak in the app or other apps); running in a broken or disconnected RDP session; out of memory for window objects.

Common situations: Long-running sessions where a leaking application exhausted the ~10k USER handle quota per session; remote desktop reconnects leaving stale session state; antivirus or shell-replacement software interfering with window creation; low system resources at startup.

Related errors


AI-assisted analysis of GraphiteEditor/Graphite@c507b35645 (2026-08-16). Data as JSON: /api/errors/8c20c51a0077a81f. Report an issue: GitHub.