libnyanpasu/clash-nyanpasu · error
Failed to register window class: {err}
Error message
Failed to register window class: {err} What it means
RegisterClassExW failed to register the Win32 window class used by the shutdown hook's hidden message-only window, returning 0. The hook converts the OS error via Error::from_win32() and aborts setup. Without the class, no shutdown-notification window can be created.
Source
Thrown at backend/tauri/src/shutdown_hook.rs:140
SHUTDOWN_HOOK_INSTANCE.set(tx).unwrap();
let h_instance = unsafe { GetModuleHandleW(std::ptr::null()) };
if h_instance.is_null() {
let err = Error::from_win32();
anyhow::bail!("Failed to get module handle: {err}");
}
let mut window_class_ex = unsafe { std::mem::zeroed::<WNDCLASSEXW>() };
window_class_ex.cbSize = std::mem::size_of::<WNDCLASSEXW>() as u32;
window_class_ex.lpszClassName = class_name.as_ptr();
window_class_ex.lpfnWndProc = Some(callback);
window_class_ex.hInstance = h_instance;
unsafe {
if RegisterClassExW(&window_class_ex) == 0 {
let err = Error::from_win32();
anyhow::bail!("Failed to register window class: {err}");
}
}
let window_name = w!("TAURI_SHUTDOWN_HOOK_WINDOW");
let hidden_window = unsafe {
CreateWindowExW(
WS_EX_TOOLWINDOW | WS_EX_NOACTIVATE,
class_name.as_ptr(),
window_name.as_ptr(),
0,
0,
0,
0,
0,
std::ptr::null_mut(),
std::ptr::null_mut(),
h_instance,
std::ptr::null_mut(),View on GitHub (pinned to f7dbce2997)
Solutions
- Check the from_win32 error text to identify the OS reason (e.g. class already exists, invalid parameter).
- Ensure setup_shutdown_hook is called once per process; unregister the class on teardown if re-registering.
- Verify the WNDCLASSEX fields (cbSize, lpfnWndProc, hInstance, lpszClassName) are valid before RegisterClassExW.
- Confirm the process has an interactive window station/desktop at the time of registration.
Example fix
// before
if RegisterClassExW(&window_class_ex) == 0 {
let err = Error::from_win32();
anyhow::bail!("Failed to register window class: {err}");
}
// after
if RegisterClassExW(&window_class_ex) == 0 {
let err = Error::from_win32();
log::warn!("window class registration failed ({err}); shutdown hook disabled");
return Ok(()); // degrade gracefully instead of failing startup
} Defensive patterns
Strategy: try-catch
Validate before calling
// ensure single registration per process
use std::sync::atomic::{AtomicBool, Ordering};
static CLASS_REGISTERED: AtomicBool = AtomicBool::new(false);
fn can_register() -> bool { !CLASS_REGISTERED.load(Ordering::SeqCst) } Try / catch
match setup_shutdown_hook() {
Ok(()) => {},
Err(e) if e.to_string().contains("register window class") => {
log::warn!("shutdown hook unavailable: {e:#}"); // degrade, don't abort app
}
Err(e) => return Err(e),
} Prevention
- Register the window class once per process lifecycle
- Log the from_win32 GetLastError code for diagnosability
- Degrade gracefully: a missing shutdown hook should not block app startup
When it happens
Trigger: Calling setup_shutdown_hook on Windows when RegisterClassExW returns 0 — e.g. invalid WNDCLASSEX fields, class name conflicts with a different style, or resource/ATOM exhaustion after many registrations in the same process/module.
Common situations: Long-running GUI sessions registering the hook repeatedly without unregistering, malformed window class configuration, or Windows desktop-station/availability issues at process startup.
Related errors
- Failed to get module handle: {err}
- Failed to create hidden window: {err}
- Local socket too many crashes
- enableLoopback exe not found
- managed target is an unsupported reparse point: {}
AI-assisted analysis of libnyanpasu/clash-nyanpasu@f7dbce2997 (2026-09-08).
Data as JSON: /api/errors/96075c22ffc04db1.
Report an issue: GitHub.