{"record":{"id":"f0f0a0d8586903eb","repo":"atuinsh/atuin","slug":"failed-to-register-sigint-handler","errorCode":null,"errorMessage":"failed to register sigint handler","messagePattern":"failed to register sigint handler","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/atuin-daemon/src/lib.rs","lineNumber":122,"sourceCode":"    .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()\n        .await\n        .expect(\"failed to listen for ctrl+c\");\n}\n","sourceCodeStart":104,"sourceCodeEnd":137,"githubUrl":"https://github.com/atuinsh/atuin/blob/202f6ad98ee0da165c35cdb2afbc5b13d6ab81a1/crates/atuin-daemon/src/lib.rs#L104-L137","documentation":"Alongside SIGTERM, atuin-daemon's shutdown_signal() registers a SIGINT listener with tokio::signal::unix::signal(SignalKind::interrupt()). tokio returns Err when the runtime lacks an IO/signal driver or the OS registration fails, and the expect panics with 'failed to register sigint handler', aborting daemon startup.","triggerScenarios":"Daemon boot inside a tokio runtime without enable_all()/enable_io(); OS-level failure installing the signal handler under resource exhaustion or a restrictive sandbox.","commonSituations":"Hosting atuin-daemon in a hand-built runtime; fd-exhausted systems at startup; embedding the daemon in another application's executor.","solutions":["Run the daemon via the shipped atuin binary, which builds the runtime with enable_all()","Build any hosting runtime with .enable_all() before awaiting daemon code","Raise LimitNOFILE / memory limits if boot-time registration fails"],"exampleFix":"// before\nlet rt = tokio::runtime::Builder::new_current_thread().build()?;\n\n// after\nlet rt = tokio::runtime::Builder::new_current_thread()\n    .enable_all()\n    .build()?;","handlingStrategy":"validation","validationCode":"let rt = tokio::runtime::Builder::new_multi_thread()\n    .enable_all()\n    .build()?;\n// daemon code must run inside this runtime for SIGINT registration to succeed","typeGuard":null,"tryCatchPattern":"match tokio::signal::unix::signal(tokio::signal::unix::SignalKind::interrupt()) {\n    Ok(int) => tokio::select! { _ = int.recv() => {} },\n    Err(e) => {\n        tracing::error!(\"sigint handler unavailable: {e}; relying on SIGTERM\");\n        tokio::signal::unix::signal(tokio::signal::unix::SignalKind::terminate())\n            .expect(\"sigterm\")\n            .recv()\n            .await;\n    }\n}","preventionTips":["Use enable_all() on runtimes that host the daemon","Keep the daemon's fd budget headroom (LimitNOFILE) so signal setup never fails","Avoid embedding daemon shutdown handling in bare executors"],"tags":["rust","tokio","signals","sigint","daemon","panic"],"backgroundTag":"tokio-signal-registration-failed","analyzedSha":"202f6ad98ee0da165c35cdb2afbc5b13d6ab81a1","analyzedAt":"2026-08-16T19:30:24.731Z","schemaVersion":2},"datasetVersion":"2026-08-16T23:17:17.608Z"}