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
- Build the tokio Runtime with .enable_all() so the signal driver is registered
- Verify the 'signal' feature is enabled for tokio in the dependency graph
- Remove pre-installed SIGHUP handlers (libc::signal, signal-hook) from wrapper code or preload libraries
- Check the sandbox/seccomp profile and file-descriptor limits
- 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
- Do not install custom SIGHUP handlers in wrapper processes; let tokio own reload-style signals
- When embedding the node, spawn signal listeners from the outermost runtime, not nested ones
- Test daemon behavior with kill -HUP in an environment matching production
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
- Failed to set up SIGINT handler
- Failed to set up SIGTERM handler
- Failed to set up Ctrl+C handler
- owner should be different from spender
- invalid block export configuration: {message}
AI-assisted analysis of linera-io/linera-protocol@6c226ddcb3 (2026-08-22).
Data as JSON: /api/errors/114721ce59cb598e.
Report an issue: GitHub.