{"record":{"id":"c5b66df5648797d3","repo":"atuinsh/atuin","slug":"failed-to-register-sigterm-handler","errorCode":null,"errorMessage":"failed to register sigterm handler","messagePattern":"failed to register sigterm handler","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/atuin-daemon/src/lib.rs","lineNumber":135,"sourceCode":"        handle,\n    )\n    .await?;\n\n    // Run the daemon event loop\n    daemon.run_event_loop().await?;\n\n    // Stop all components on shutdown\n    daemon.stop_components().await;\n\n    tracing::info!(\"daemon shut down complete\");\n    Ok(())\n}\n\n/// Wait for a shutdown signal (Ctrl+C or SIGTERM).\n#[cfg(unix)]\nasync fn shutdown_signal() {\n    let mut term = tokio::signal::unix::signal(tokio::signal::unix::SignalKind::terminate())\n        .expect(\"failed to register sigterm handler\");\n    let mut int = tokio::signal::unix::signal(tokio::signal::unix::SignalKind::interrupt())\n        .expect(\"failed to register sigint handler\");\n\n    tokio::select! {\n        _ = term.recv() => {},\n        _ = int.recv() => {},\n    }\n}\n\n/// Wait for a shutdown signal (Ctrl+C).\n#[cfg(not(unix))]\nasync fn shutdown_signal() {\n    tokio::signal::ctrl_c().await.expect(\"failed to listen for ctrl+c\");\n}\n","sourceCodeStart":117,"sourceCodeEnd":150,"githubUrl":"https://github.com/atuinsh/atuin/blob/c0c717ab04c881764bcad4b3d169a507e2432643/crates/atuin-daemon/src/lib.rs#L117-L150","documentation":"`shutdown_signal()` in the Atuin daemon registers a SIGTERM handler via `tokio::signal::unix::signal`. Panicking here means the OS refused to install the signal handler — the signal event source could not be created. Without it the daemon cannot shut down gracefully on SIGTERM.","triggerScenarios":"`SignalKind::terminate()` handler registration failing inside `shutdown_signal()` during `boot()` — typically when tokio's signal driver is unavailable or the process hit a resource/signal limit.","commonSituations":"Calling daemon boot outside a tokio runtime with the signal driver enabled (e.g. `current_thread` runtime built without `rt` features or via block_on misuse); RLIMIT_SIGPENDING exhaustion from leaked signal handlers; unusual runtimes without full signal support.","solutions":["Ensure the daemon runs inside a properly configured tokio multi-thread runtime with the `signal` feature","Check `ulimit -i` (RLIMIT_SIGPENDING) and raise it if exhausted","Investigate leaked signal handler registrations in long-running wrapper processes","Update tokio — older versions had signal-driver edge cases"],"exampleFix":"// before\n#[tokio::main]\nasync fn main() { /* runtime without io/signal driver */ }\n// after\n#[tokio::main(flavor = \"multi_thread\")]\nasync fn main() { /* ensure tokio features \"rt-multi-thread\", \"signal\", \"macros\" */ }","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"// Use the Result-returning API instead of expect:\nlet mut term = tokio::signal::unix::signal(SignalKind::terminate())\n    .map_err(|e| BootError::SignalHandler(e))?;","preventionTips":["Enable tokio features: rt-multi-thread, macros, signal","Check RLIMIT_SIGPENDING (`ulimit -i`) on hosts running many processes","Avoid nesting signal registrations in loops without dropping old handlers"],"tags":["signal","tokio","panic","daemon"],"backgroundTag":"module-init-failed","analyzedSha":"c0c717ab04c881764bcad4b3d169a507e2432643","analyzedAt":"2026-09-12T07:40:01.341Z","contentChangedAt":"2026-09-12T07:40:01.341Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}