linera-io/linera-protocol · error

Failed to set up Ctrl+C handler

Error message

Failed to set up Ctrl+C handler

What it means

Panics when tokio::signal::ctrl_c().await returns an Err on Windows inside listen_for_shutdown_signals. ctrl_c() fails at registration time when SetConsoleCtrlHandler cannot install the handler — restricted environments, service contexts without a console, handler-table exhaustion, or a runtime without the IO/signal driver. The panic runs the drop_guard, cancelling the shutdown token and starting an immediate shutdown.

Source

Thrown at linera-base/src/lib.rs:197

        let mut sigint =
            unix::signal(unix::SignalKind::interrupt()).expect("Failed to set up SIGINT handler");
        let mut sigterm =
            unix::signal(unix::SignalKind::terminate()).expect("Failed to set up SIGTERM handler");
        let mut sighup =
            unix::signal(unix::SignalKind::hangup()).expect("Failed to set up SIGHUP handler");

        tokio::select! {
            _ = sigint.recv() => debug!("Received SIGINT"),
            _ = sigterm.recv() => debug!("Received SIGTERM"),
            _ = sighup.recv() => debug!("Received SIGHUP"),
        }
    }

    #[cfg(windows)]
    {
        tokio::signal::ctrl_c()
            .await
            .expect("Failed to set up Ctrl+C handler");
        debug!("Received Ctrl+C");
    }
}

/// Registers every metric this crate declares.
///
/// Without this, a metric is only exported after the code path that observes it has run, so a
/// rarely-taken path leaves its panels blank and makes a routine restart look like the metric
/// was removed.
#[cfg(with_metrics)]
pub fn init_metrics() {
    data_types::metrics::init_metrics();
    panic_hook::metrics::init_metrics();
}

View on GitHub (pinned to 6c226ddcb3)

Solutions

  1. Build the tokio Runtime with .enable_all() before spawning the listener
  2. If running as a Windows service, handle service control events via the windows-service crate instead of relying on console Ctrl+C
  3. Remove competing console-handler registrations from other crates or preload DLLs
  4. Run in an interactive console session to confirm the handler installs, then re-enable the service context
  5. Treat a panicked listener task as fatal — the shutdown token was cancelled, so exit cleanly

Example fix

// before
let rt = tokio::runtime::Builder::new_multi_thread().build()?; // no enable_all
rt.spawn(linera_base::listen_for_shutdown_signals(token));

// after
let rt = tokio::runtime::Builder::new_multi_thread()
    .enable_all()
    .build()?;
rt.spawn(linera_base::listen_for_shutdown_signals(token));
// If running as a Windows service, additionally subscribe to service stop events
// instead of relying solely on Ctrl+C.
Defensive patterns

Strategy: validation

Validate before calling

// On Windows, the runtime must have the IO driver for ctrl_c registration:
let rt = tokio::runtime::Builder::new_multi_thread()
    .enable_all()
    .build()?;
rt.spawn(linera_base::listen_for_shutdown_signals(token));

Try / catch

let handle = tokio::spawn(listen_for_shutdown_signals(token));
if let Err(e) = handle.await {
    if e.is_panic() {
        // ctrl_c handler registration failed; token cancelled via drop_guard.
        log::error!("ctrl_c registration failed: {e}");
        graceful_shutdown().await;
    }
}

Prevention

When it happens

Trigger: Running the node as a Windows service or in a session without an interactive console; a runtime built without .enable_all() so the signal infrastructure is absent; a sandboxed Windows environment ( restricted AppContainer) denying SetConsoleCtrlHandler; too many console handlers already registered by other libraries.

Common situations: Windows CI agents running the node headless; embedding linera-base in a GUI application or service wrapper on Windows; multiple signal-handling crates (ctrlc, windows-service) competing for console-handler slots.

Related errors


AI-assisted analysis of linera-io/linera-protocol@6c226ddcb3 (2026-08-22). Data as JSON: /api/errors/85610a9e98e138f5. Report an issue: GitHub.