tracel-ai/burn · error

failed to install Ctrl+C handler

Error message

failed to install Ctrl+C handler

What it means

This panic comes from tokio's ctrl_c() inside os_shutdown_signal(), which installs a SIGINT handler for graceful shutdown. Installation can only fail if the tokio runtime has no signal driver (e.g. called via block_on with runtime disabled or io/signal driver not enabled). The library panics because shutdown signaling is considered essential and unrecoverable.

Source

Thrown at crates/burn-communication/src/util.rs:6

/// Utilities to help handle communication termination.
pub async fn os_shutdown_signal() {
    let ctrl_c = async {
        tokio::signal::ctrl_c()
            .await
            .expect("failed to install Ctrl+C handler");
    };

    #[cfg(unix)]
    let terminate = async {
        tokio::signal::unix::signal(tokio::signal::unix::SignalKind::terminate())
            .expect("failed to install signal handler")
            .recv()
            .await;
    };

    #[cfg(not(unix))]
    let terminate = std::future::pending::<()>();

    tokio::select! {
        _ = ctrl_c => {},
        _ = terminate => {},
    }
}

View on GitHub (pinned to d16f7ba2ed)

Solutions

  1. Enable tokio features 'signal' (and 'io-util'/'rt-multi-thread' as needed) in Cargo.toml and build the runtime with the default builder so the signal driver is registered.
  2. Ensure os_shutdown_signal is awaited inside a tokio runtime context, not on a bare std thread.
  3. If signal handling must be optional, replace the expect with graceful error propagation in a forked copy of util.rs.

Example fix

// before (custom runtime without signal driver)
let rt = tokio::runtime::Builder::new_current_thread().enable_io().build()?;
// after
let rt = tokio::runtime::Builder::new_multi_thread().enable_all().build()?;
// and in Cargo.toml: tokio = { version = "1", features = ["full"] }
Defensive patterns

Strategy: validation

Validate before calling

// Ensure a full-featured tokio runtime wraps the call
assert!(tokio::runtime::Handle::try_current().is_ok(), "must run inside a tokio runtime");

Prevention

When it happens

Trigger: Calling start_iroh_async or start_websocket_async inside a runtime built without the signal feature, or on a runtime lacking signal handling support; tokio::signal::ctrl_c() returns Err before awaiting the signal.

Common situations: Embedding burn's communication server in a custom tokio runtime with feature flags stripped (no 'signal' support), using a current-thread runtime assembled manually, or running under an environment that forbids signal handler installation.

Related errors


AI-assisted analysis of tracel-ai/burn@d16f7ba2ed (2026-09-05). Data as JSON: /api/errors/15d4fd0094169623. Report an issue: GitHub.