linera-io/linera-protocol · error

Failed to set up SIGHUP handler

Error message

Failed to set up SIGHUP handler

What it means

Panics when tokio::signal::unix::signal(SignalKind::hangup()) fails to install a SIGHUP handler in listen_for_shutdown_signals. Like the SIGINT/SIGTERM cases, this is a registration-time failure: the tokio runtime has no signal driver, the global signal registry could not be created, or the environment blocks handler installation. The drop_guard then cancels the CancellationToken, so the process starts an immediate shutdown.

Source

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

/// Helper function for allocative.
pub fn visit_allocative_simple<T>(_: &T, visitor: &mut allocative::Visitor<'_>) {
    visitor.visit_simple_sized::<T>();
}

/// Listens for shutdown signals, and notifies the [`CancellationToken`] if one is
/// received.
#[cfg(not(target_arch = "wasm32"))]
pub async fn listen_for_shutdown_signals(shutdown_sender: CancellationToken) {
    let _shutdown_guard = shutdown_sender.drop_guard();

    #[cfg(unix)]
    {
        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.

View on GitHub (pinned to 6c226ddcb3)

Solutions

  1. Build the tokio Runtime with .enable_all() so the signal driver is registered
  2. Verify the 'signal' feature is enabled for tokio in the dependency graph
  3. Remove pre-installed SIGHUP handlers (libc::signal, signal-hook) from wrapper code or preload libraries
  4. Check the sandbox/seccomp profile and file-descriptor limits
  5. Monitor the spawned task's JoinHandle and exit cleanly — the shutdown token has already been cancelled by the drop guard

Example fix

// before
let rt = tokio::runtime::Runtime::new().unwrap(); // no signal driver in some configs
rt.spawn(listen_for_shutdown_signals(token));

// after
#[tokio::main] // #[tokio::main] and #[tokio::test] call enable_all() for you
async fn main() {
    tokio::spawn(listen_for_shutdown_signals(token));
    // ...
}
Defensive patterns

Strategy: validation

Validate before calling

// Ensure the runtime the listener runs on was built with the signal driver:
let rt = tokio::runtime::Builder::new_multi_thread()
    .enable_all()
    .build()?;
rt.spawn(linera_base::listen_for_shutdown_signals(token));

Try / catch

match tokio::spawn(listen_for_shutdown_signals(token)).await {
    Ok(()) => {}
    Err(e) if e.is_panic() => {
        // SIGHUP registration failed and the token fired: treat as fatal,
        // do not respawn in a loop.
        std::process::exit(1);
    }
    Err(e) => panic!("listener task failed: {e}"),
}

Prevention

When it happens

Trigger: Running the signal listener on a runtime without .enable_all(); nested runtimes (spawning the listener inside Runtime::block_on of a runtime lacking the signal driver); sandboxes denying sigaction; EMFILE at process start. SITESPECIFIC: daemons that re-exec or fork (SIGHUP is the reload signal) sometimes install their own SIGHUP handler first, exhausting or conflicting with tokio's registry.

Common situations: Running the node as a systemd/init service where the supervisor or a wrapper script also manipulates SIGHUP; custom embedding of linera-base with a manually built runtime; minimal base images (distroless, scratch) with restricted syscall profiles.

Related errors


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