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

  1. Check the from_win32 error text to identify the OS reason (e.g. class already exists, invalid parameter).
  2. Ensure setup_shutdown_hook is called once per process; unregister the class on teardown if re-registering.
  3. Verify the WNDCLASSEX fields (cbSize, lpfnWndProc, hInstance, lpszClassName) are valid before RegisterClassExW.
  4. 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

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


AI-assisted analysis of libnyanpasu/clash-nyanpasu@f7dbce2997 (2026-09-08). Data as JSON: /api/errors/96075c22ffc04db1. Report an issue: GitHub.