atuinsh/atuin · error

failed to register signal handler

Error message

failed to register signal handler

What it means

`shutdown_signal` on Unix registers a SIGTERM handler with tokio and panics via `.expect("failed to register signal handler")` if registration fails. tokio's signal registration fails when the OS refuses the handler installation — typically when not running on a real OS thread setup that supports signals, when the process has no permission for the signal, or when signal dispositions are externally controlled.

Solutions

  1. Check the container/sandbox security profile allows sigaction for SIGTERM/SIGINT
  2. Ensure the server runs on a proper multi-thread tokio runtime
  3. Replace expect with graceful degradation: log a warning and fall back to waiting on ctrl_c or indefinitely

Example fix

// before
let mut term = signal::unix::signal(signal::unix::SignalKind::terminate())
    .expect("failed to register signal handler");
// after
let mut term = signal::unix::signal(signal::unix::SignalKind::terminate())
    .unwrap_or_else(|e| {
        eprintln!("failed to register SIGTERM handler: {e}; skipping graceful shutdown on SIGTERM");
        signal::unix::signal(signal::unix::SignalKind::hangup()).expect("failed to register signal handler")
    });
Defensive patterns

Strategy: try-catch

Validate before calling

// check before serving (unix)
let term_ok = signal::unix::signal(signal::unix::SignalKind::terminate()).is_ok();

Try / catch

match signal::unix::signal(signal::unix::SignalKind::terminate()) {
    Ok(mut s) => { /* proceed with shutdown select */ }
    Err(e) => eprintln!("SIGTERM handler unavailable: {e}"),
}

Prevention

When it happens

Trigger: Calling `launch` or `launch_metrics_server` in an environment where `signal::unix::signal(SignalKind::terminate())` returns Err — e.g. running inside restricted containers/seccomp sandboxes that block sigaction, or after tokio runtime misuse.

Common situations: Docker containers with hardened seccomp profiles, restricted CI runners, unusual sandboxing (gVisor), or embedding the server in a non-tokio runtime context.

Related errors


AI-assisted analysis of atuinsh/atuin@900007c480 (2026-09-19). Data as JSON: /api/errors/116a1333087d70df. Report an issue: GitHub.

Appendix: source

Thrown at crates/atuin-server/src/lib.rs:30

mod handlers;
mod metrics;
mod router;
mod trace;

pub mod db;

pub use settings::{Settings, example_config};

pub mod settings;

use tokio::net::TcpListener;
use tokio::signal;

#[cfg(target_family = "unix")]
async fn shutdown_signal() {
    let mut term = signal::unix::signal(signal::unix::SignalKind::terminate())
        .expect("failed to register signal handler");
    let mut interrupt = signal::unix::signal(signal::unix::SignalKind::interrupt())
        .expect("failed to register signal handler");

    tokio::select! {
        _ = term.recv() => {},
        _ = interrupt.recv() => {},
    };
    eprintln!("Shutting down gracefully...");
}

#[cfg(target_family = "windows")]
async fn shutdown_signal() {
    signal::windows::ctrl_c().expect("failed to register signal handler").recv().await;
    eprintln!("Shutting down gracefully...");
}

pub async fn launch(settings: Settings, addr: SocketAddr) -> Result<()> {
    launch_with_tcp_listener(

View on GitHub (pinned to 900007c480)