RightNow-AI/openfang · error
Failed to listen for SIGTERM
Error message
Failed to listen for SIGTERM
What it means
tokio's signal(SignalKind::terminate()) registers a handler for SIGTERM via the OS (signalfd/kevent). It returns Err when the process cannot register the signal handler — typically when running outside a proper process context (e.g. not a session leader, resource limits, or on platforms where signal registration is unsupported). The code panics with this expect message instead of returning the error.
Source
Thrown at crates/openfang-api/src/server.rs:957
fn restrict_permissions(_path: &Path) {}
/// Read daemon info from the standard location.
pub fn read_daemon_info(home_dir: &Path) -> Option<DaemonInfo> {
let info_path = home_dir.join("daemon.json");
let contents = std::fs::read_to_string(info_path).ok()?;
serde_json::from_str(&contents).ok()
}
/// Wait for an OS termination signal OR an API shutdown request.
///
/// On Unix: listens for SIGINT, SIGTERM, and API notify.
/// On Windows: listens for Ctrl+C and API notify.
async fn shutdown_signal(api_shutdown: Arc<tokio::sync::Notify>) {
#[cfg(unix)]
{
use tokio::signal::unix::{signal, SignalKind};
let mut sigint = signal(SignalKind::interrupt()).expect("Failed to listen for SIGINT");
let mut sigterm = signal(SignalKind::terminate()).expect("Failed to listen for SIGTERM");
tokio::select! {
_ = sigint.recv() => {
info!("Received SIGINT (Ctrl+C), shutting down...");
}
_ = sigterm.recv() => {
info!("Received SIGTERM, shutting down...");
}
_ = api_shutdown.notified() => {
info!("Shutdown requested via API, shutting down...");
}
}
}
#[cfg(not(unix))]
{
tokio::select! {
_ = tokio::signal::ctrl_c() => {View on GitHub (pinned to acf2587e46)
Solutions
- Check container/sandbox security profile allows signalfd / signal handler registration (adjust seccomp or AppArmor profile).
- Check ulimit -i / RLIMIT_SIGPENDING; raise limits if exhausted.
- Replace .expect with graceful error propagation and fall back to Ctrl+C-only handling (SIGINT) or polling shutdown flags.
- Ensure tokio's 'signal' feature is enabled and a reactor is running before registering handlers.
Example fix
// before
let mut sigterm = signal(SignalKind::terminate()).expect("Failed to listen for SIGTERM");
// after
let mut sigterm = match signal(SignalKind::terminate()) {
Ok(s) => s,
Err(e) => {
eprintln!("SIGTERM handling unavailable ({e}); only Ctrl+C will stop the daemon");
return;
}
}; Defensive patterns
Strategy: try-catch
Validate before calling
// Unix: verify the process can register a SIGTERM handler before entering the daemon loop
#[cfg(unix)]
fn can_listen_sigterm() -> bool {
use tokio::signal::unix::{signal, SignalKind};
signal(SignalKind::terminate()).is_ok()
} Try / catch
// return Result instead of expect
fn shutdown_signal(api_shutdown: Arc<tokio::sync::Notify>) -> Result<(), std::io::Error> {
#[cfg(unix)]
{
use tokio::signal::unix::{signal, SignalKind};
let mut sigterm = signal(SignalKind::terminate())?; // propagated, no panic
// ...select! as before
}
Ok(())
} Prevention
- Never .expect on signal registration in daemon code; propagate or degrade gracefully.
- Test daemon startup inside your actual container/sandbox security profile.
- Raise RLIMIT_SIGPENDING on hosts running many processes.
- Keep tokio 'signal' feature enabled and register handlers after runtime init.
When it happens
Trigger: Calling shutdown_signal() on a Unix platform where tokio::signal::unix::signal(SignalKind::terminate()) fails: e.g. RLIMIT_SIGPENDING exhaustion, running in restricted sandbox/container (seccomp blocking signalfd), or on an unsupported Unix target.
Common situations: Running the daemon in a heavily restricted container (gVisor, minimal seccomp profiles), under PID/resource limit starvation, or on exotic Unix targets where tokio's signal driver cannot initialize.
Related errors
- Failed to listen for SIGINT
- Failed to create Tokio runtime
- Failed to build HTTP client
- Failed to build HTTP client
- Failed to draw
AI-assisted analysis of RightNow-AI/openfang@acf2587e46 (2026-09-02).
Data as JSON: /api/errors/541fe8f2160d3fe1.
Report an issue: GitHub.