libnyanpasu/clash-nyanpasu · warning

Failed to send initd signal

Error message

Failed to send initd signal: {e}

What it means

The oneshot initd_tx channel used to signal that the shutdown-hook window finished initializing rejected the send, meaning the receiver was already dropped (e.g. the awaiting thread errored, panicked, or the setup future was cancelled).

Solutions

  1. Check whether the receiver future/thread exited early and fix the underlying error it reported first.
  2. Treat a dropped receiver as cancellation: log and return cleanly instead of propagating as fatal, since the hook is already set up structurally.
  3. Ensure the waiter is spawned/awaited before the window thread runs, or use a tolerant send (ignore SendError).
  4. Add logging on the receive side to detect premature teardown.

Example fix

// before
if let Err(e) = initd_tx.send(()) {
    anyhow::bail!("Failed to send initd signal: {e}");
}
// after
if let Err(e) = initd_tx.send(()) {
    log::debug!("initd receiver dropped, hook teardown in progress: {e}");
}
Defensive patterns

Strategy: try-catch

Validate before calling

// keep receiver alive until send completes
let (initd_tx, initd_rx) = tokio::sync::oneshot::channel::<()>();
assert!(!initd_rx.is_terminated(), "receiver already dropped");

Try / catch

if let Err(e) = initd_tx.send(()) {
    // SendError only occurs when receiver dropped: treat as cancellation
    log::debug!("init signal receiver gone: {}", e);
}

Prevention

When it happens

Trigger: Calling setup_shutdown_hook when the receiving side of initd_tx has been dropped before send(()) succeeds — the spawn wrapper cancelled, or the waiter thread exited early on another error.

Common situations: Startup races where the bootstrap task is torn down while the hook thread is still initializing, or a panic in the code awaiting the init signal.

Related errors


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

Appendix: source

Thrown at backend/tauri/src/shutdown_hook.rs:172

            0,
            std::ptr::null_mut(),
            std::ptr::null_mut(),
            h_instance,
            std::ptr::null_mut(),
        )
    };
    if hidden_window.is_null() {
        let err = Error::from_win32();
        anyhow::bail!("Failed to create hidden window: {err}");
    }

    let window_handle = WindowHandle {
        hwnd: hidden_window,
        h_instance,
    };

    if let Err(e) = initd_tx.send(()) {
        anyhow::bail!("Failed to send initd signal: {e}");
    }

    let mut msg = unsafe { std::mem::zeroed::<MSG>() };
    unsafe {
        loop {
            let result = GetMessageW(&mut msg, window_handle.hwnd, 0, 0);
            if result > 0 {
                TranslateMessage(&msg);
                DispatchMessageW(&msg);
            } else {
                let err = Error::from_win32();
                tracing::error!(
                    "GetMessageW failed with {result}, shutdown hook thread exiting: {err}"
                );
                break;
            }
        }
    }

View on GitHub (pinned to f7dbce2997)