{"record":{"id":"85610a9e98e138f5","repo":"linera-io/linera-protocol","slug":"failed-to-set-up-ctrl-c-handler","errorCode":null,"errorMessage":"Failed to set up Ctrl+C handler","messagePattern":"Failed to set up Ctrl\\+C handler","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"linera-base/src/lib.rs","lineNumber":197,"sourceCode":"        let mut sigint =\n            unix::signal(unix::SignalKind::interrupt()).expect(\"Failed to set up SIGINT handler\");\n        let mut sigterm =\n            unix::signal(unix::SignalKind::terminate()).expect(\"Failed to set up SIGTERM handler\");\n        let mut sighup =\n            unix::signal(unix::SignalKind::hangup()).expect(\"Failed to set up SIGHUP handler\");\n\n        tokio::select! {\n            _ = sigint.recv() => debug!(\"Received SIGINT\"),\n            _ = sigterm.recv() => debug!(\"Received SIGTERM\"),\n            _ = sighup.recv() => debug!(\"Received SIGHUP\"),\n        }\n    }\n\n    #[cfg(windows)]\n    {\n        tokio::signal::ctrl_c()\n            .await\n            .expect(\"Failed to set up Ctrl+C handler\");\n        debug!(\"Received Ctrl+C\");\n    }\n}\n\n/// Registers every metric this crate declares.\n///\n/// Without this, a metric is only exported after the code path that observes it has run, so a\n/// rarely-taken path leaves its panels blank and makes a routine restart look like the metric\n/// was removed.\n#[cfg(with_metrics)]\npub fn init_metrics() {\n    data_types::metrics::init_metrics();\n    panic_hook::metrics::init_metrics();\n}\n","sourceCodeStart":179,"sourceCodeEnd":212,"githubUrl":"https://github.com/linera-io/linera-protocol/blob/6c226ddcb332ef55118dc8d0aafbd093d5420899/linera-base/src/lib.rs#L179-L212","documentation":"Panics when tokio::signal::ctrl_c().await returns an Err on Windows inside listen_for_shutdown_signals. ctrl_c() fails at registration time when SetConsoleCtrlHandler cannot install the handler — restricted environments, service contexts without a console, handler-table exhaustion, or a runtime without the IO/signal driver. The panic runs the drop_guard, cancelling the shutdown token and starting an immediate shutdown.","triggerScenarios":"Running the node as a Windows service or in a session without an interactive console; a runtime built without .enable_all() so the signal infrastructure is absent; a sandboxed Windows environment ( restricted AppContainer) denying SetConsoleCtrlHandler; too many console handlers already registered by other libraries.","commonSituations":"Windows CI agents running the node headless; embedding linera-base in a GUI application or service wrapper on Windows; multiple signal-handling crates (ctrlc, windows-service) competing for console-handler slots.","solutions":["Build the tokio Runtime with .enable_all() before spawning the listener","If running as a Windows service, handle service control events via the windows-service crate instead of relying on console Ctrl+C","Remove competing console-handler registrations from other crates or preload DLLs","Run in an interactive console session to confirm the handler installs, then re-enable the service context","Treat a panicked listener task as fatal — the shutdown token was cancelled, so exit cleanly"],"exampleFix":"// before\nlet rt = tokio::runtime::Builder::new_multi_thread().build()?; // no enable_all\nrt.spawn(linera_base::listen_for_shutdown_signals(token));\n\n// after\nlet rt = tokio::runtime::Builder::new_multi_thread()\n    .enable_all()\n    .build()?;\nrt.spawn(linera_base::listen_for_shutdown_signals(token));\n// If running as a Windows service, additionally subscribe to service stop events\n// instead of relying solely on Ctrl+C.","handlingStrategy":"validation","validationCode":"// On Windows, the runtime must have the IO driver for ctrl_c registration:\nlet rt = tokio::runtime::Builder::new_multi_thread()\n    .enable_all()\n    .build()?;\nrt.spawn(linera_base::listen_for_shutdown_signals(token));","typeGuard":null,"tryCatchPattern":"let handle = tokio::spawn(listen_for_shutdown_signals(token));\nif let Err(e) = handle.await {\n    if e.is_panic() {\n        // ctrl_c handler registration failed; token cancelled via drop_guard.\n        log::error!(\"ctrl_c registration failed: {e}\");\n        graceful_shutdown().await;\n    }\n}","preventionTips":["Run the node in an interactive console during development to confirm Ctrl+C works before service deployment","For Windows services, subscribe to service control stop events separately instead of relying on console Ctrl+C","Limit the number of crates registering console handlers in the same process"],"tags":["rust","tokio","signals","windows","ctrl-c","startup","panic"],"backgroundTag":"signal-handler-registration-failed","analyzedSha":"6c226ddcb332ef55118dc8d0aafbd093d5420899","analyzedAt":"2026-08-22T22:49:09.787Z","schemaVersion":2},"datasetVersion":"2026-08-23T01:17:44.959Z"}