{"record":{"id":"766e8623edcdf189","repo":"loco-rs/loco","slug":"failed-to-install-signal-handler","errorCode":null,"errorMessage":"failed to install signal handler","messagePattern":"failed to install signal handler","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/boot.rs","lineNumber":588,"sourceCode":"}\n\n/// Waits for a shutdown signal, either via Ctrl+C or termination signal.\n///\n/// # Panics\n///\n/// This function will panic if it fails to install the signal handlers for\n/// Ctrl+C or the terminate signal on Unix-based systems.\npub async fn shutdown_signal() {\n    let ctrl_c = async {\n        signal::ctrl_c()\n            .await\n            .expect(\"failed to install Ctrl+C handler\");\n    };\n\n    #[cfg(unix)]\n    let terminate = async {\n        signal::unix::signal(signal::unix::SignalKind::terminate())\n            .expect(\"failed to install signal handler\")\n            .recv()\n            .await;\n    };\n\n    #[cfg(not(unix))]\n    let terminate = std::future::pending::<()>();\n\n    tokio::select! {\n        () = ctrl_c => {},\n        () = terminate => {},\n    }\n}\n\npub struct MiddlewareInfo {\n    pub id: String,\n    pub enabled: bool,\n    pub detail: String,\n}","sourceCodeStart":570,"sourceCodeEnd":606,"githubUrl":"https://github.com/loco-rs/loco/blob/23639d1e360dbc618073642b507d6f8664adbaff/src/boot.rs#L570-L606","documentation":"This panic comes from installing the SIGTERM (terminate) listener inside loco's `shutdown_signal` future via tokio's `signal::unix::signal(SignalKind::terminate())`. If the OS refuses to register the signal handler — most commonly because tokio's IO/signal driver is not running (no reactor in the current worker/thread) or the process exhausted signal-mask resources — `.expect()` panics with this message, aborting server startup.","triggerScenarios":"Calling `serve`/`start` (or anything awaiting `shutdown_signal`) outside a multi-threaded tokio runtime, or on a thread without an active tokio reactor (e.g. `#[tokio::test(flavor = \"current_thread\")]` with signal use from a blocking context, or `Runtime::new()` used only via `block_on` on a thread where the signal driver was shut down).","commonSituations":"Embedding a Loco server inside another application's custom runtime setup; running the app in a minimal container where a nonstandard runtime wrapper is used; writing custom main() that spawns `serve` on a current-thread runtime and shuttles work across threads.","solutions":["Run `serve`/`start` on the default multi-threaded tokio runtime (`#[tokio::main]` or `loco`'s own `loco_rs::boot::run` entrypoint) so the signal driver has a reactor","If using a custom runtime, create it with the `rt-multi-thread` and `signal` features enabled and keep signal listening on a runtime worker thread","Wrap the shutdown-signal setup in `tokio::spawn` from within the runtime instead of installing handlers from a foreign thread","Avoid `#[tokio::test(flavor = \"current_thread\")]` paths that call `shutdown_signal` directly; use the full boot helper instead"],"exampleFix":"// before\nstd::thread::spawn(|| {\n    let rt = tokio::runtime::Builder::new_current_thread().build().unwrap();\n    rt.block_on(loco_rs::boot::start(app)); // panics: no signal reactor\n});\n// after\n#[tokio::main]\nasync fn main() -> loco_rs::Result<()> {\n    loco_rs::boot::start(app).await // multi-thread runtime, signal driver available\n}","handlingStrategy":"try-catch","validationCode":"// Rust: verify the runtime can host the signal driver before booting\nlet rt = tokio::runtime::Handle::try_current()\n    .expect(\"shutdown_signal must run inside a tokio runtime\");\nassert!(!tokio::runtime::Handle::current().runtime_flavor()\n    == tokio::runtime::RuntimeFlavor::CurrentThread || cfg!(debug_assertions));","typeGuard":null,"tryCatchPattern":"// Catch panics during boot and report a clear message\nlet result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {\n    // start server\n}));\nif result.is_err() { eprintln!(\"server boot failed: signal handler could not be installed; run on a multi-threaded tokio runtime\"); }","preventionTips":["Always boot Loco via its own main/run entrypoints on `#[tokio::main]`","Enable tokio's `signal` and `rt-multi-thread` features","Never install signal handlers from threads outside the runtime"],"tags":["rust","signals","tokio","panic"],"backgroundTag":"unsupported-platform","analyzedSha":"23639d1e360dbc618073642b507d6f8664adbaff","analyzedAt":"2026-09-12T01:47:20.769Z","contentChangedAt":"2026-09-12T01:47:20.769Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}