loco-rs/loco · error

failed to install Ctrl+C handler

Error message

failed to install Ctrl+C handler

What it means

Panic in `shutdown_signal` when the tokio Ctrl+C (or Unix SIGTERM) signal handler cannot be installed. The function promises graceful shutdown, so rather than continuing without signal handling it panics, per its documented behavior.

Solutions

  1. Run the server in an environment that permits installing signal handlers (check container security profiles/seccomp)
  2. Check process resource limits (`ulimit -i`) and the OS for signal-related restrictions
  3. Bypass by sending signals differently or patching `shutdown_signal` to log-and-continue if your deployment never needs graceful shutdown
  4. Update tokio if the failure comes from a known tokio signal-handling bug

Example fix

// before
signal::ctrl_c().await.expect("failed to install Ctrl+C handler");
// after
if signal::ctrl_c().await.is_err() {
    tracing::warn!("Ctrl+C handler unavailable; graceful shutdown disabled");
    std::future::pending::<()>().await;
}
Defensive patterns

Strategy: try-catch

Try / catch

tokio::select! {
    _ = shutdown_signal() => { /* graceful shutdown */ }
    _ = std::future::pending::<()>() => {}
} // wrap the runner in a supervisor that restarts and alerts if the process panics here

Prevention

When it happens

Trigger: Starting the server via `cargo loco start` / `serve` in an environment where the signal handler registration fails — typically OS-level restrictions, resource exhaustion, or runtimes lacking signal support.

Common situations: Running inside restricted containers/sandboxes (some minimal containers, seccomp profiles, WSL edge cases); hitting RLIMIT on signal descriptors; unusual process supervisors blocking signal APIs.

Related errors


AI-assisted analysis of loco-rs/loco@23639d1e36 (2026-09-12). Data as JSON: /api/errors/d84308eb9a3affe5. Report an issue: GitHub.

Appendix: source

Thrown at src/boot.rs:582

    Ok(())
}

#[must_use]
pub fn list_endpoints<H: Hooks>(ctx: &AppContext) -> Vec<ListRoutes> {
    H::routes(ctx).collect()
}

/// Waits for a shutdown signal, either via Ctrl+C or termination signal.
///
/// # Panics
///
/// This function will panic if it fails to install the signal handlers for
/// Ctrl+C or the terminate signal on Unix-based systems.
pub async fn shutdown_signal() {
    let ctrl_c = async {
        signal::ctrl_c()
            .await
            .expect("failed to install Ctrl+C handler");
    };

    #[cfg(unix)]
    let terminate = async {
        signal::unix::signal(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 23639d1e36)