libnyanpasu/clash-nyanpasu · warning

Failed to send initd signal: {e}

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).

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)

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.