bootandy/dust · error
Error setting Ctrl-C handler
Error message
Error setting Ctrl-C handler
What it means
This panic comes from `.expect()` on the `Result` returned by `ctrlc::set_handler`, which registers a SIGINT (Ctrl-C) handler for the process. The ctrlc crate throws this error when it fails to install the OS-level signal handler — typically because the underlying OS API (signal/sigaction on Unix, SetConsoleCtrlHandler on Windows) failed, or because the internal wakeup pipe/socket could not be created.
Solutions
- Check the environment the program runs in: remove seccomp/sandbox syscall restrictions blocking pipe2 or signal installation, and raise the file-descriptor limit (ulimit -n).
- Call `ctrlc::set_handler` and handle the Err case gracefully instead of panicking, so the tool still runs (just without Ctrl-C handling): `if let Err(e) = ctrlc::set_handler(...) { eprintln!("warning: Ctrl-C handling unavailable: {e}"); }`.
- Ensure ctrlc runs only once per process and before threads that matter are spawned; a second set_handler call or a mis-sequenced init can fail.
- Update the ctrlc crate to the latest version; older versions had platform-specific handler-installation bugs.
- If the environment genuinely cannot support signal handlers (e.g. some embedded/WASI targets), drop the ctrlc dependency or gate it behind a feature flag / target check.
Example fix
// before
ctrlc::set_handler(move || {
println!("\nAborting");
process::exit(1);
})
.expect("Error setting Ctrl-C handler");
// after
if let Err(e) = ctrlc::set_handler(move || {
println!("\nAborting");
process::exit(1);
}) {
eprintln!("warning: could not install Ctrl-C handler: {e}");
} Defensive patterns
Strategy: fallback
Validate before calling
// No portable pre-check exists; detect the environment that breaks ctrlc:
// e.g. check fd availability before startup
match std::fs::File::create("/dev/null") {
Ok(_) => {},
Err(e) => eprintln!("fd exhaustion likely ({e}); signal handler may fail to install"),
} Type guard
fn ctrlc_supported() -> bool {
#[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows"))]
{ true }
#[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows")))]
{ false }
} Try / catch
match ctrlc::set_handler(|| {
eprintln!("\nAborting");
std::process::exit(1);
}) {
Ok(()) => {}
Err(e) => eprintln!("warning: Ctrl-C handling unavailable: {e}"),
} Prevention
- Never `.expect()`/`.unwrap()` on set_handler in a CLI tool — degrade to running without a handler instead of aborting startup.
- Avoid running signal-handler setup inside restricted sandboxes/seccomp profiles; test container images with the same syscall filters as production.
- Keep the ctrlc crate updated and register the handler once, early in main, before spawning worker threads.
- Monitor file-descriptor usage; fd exhaustion breaks ctrlc's internal self-pipe.
When it happens
Trigger: Calling `ctrlc::set_handler` when: (1) the OS refuses to install a signal handler (e.g. signal/sigaction returns an error), (2) the crate cannot create its internal self-pipe (pipe/socketpair failure, often fd exhaustion or a hardened seccomp/sandbox blocking pipe2), (3) running in an environment without a proper signal mechanism (some containers, CI sandboxes, or processes with a masked/disabled signal mask), or (4) set_handler is invoked in a context where registering handlers is not permitted.
Common situations: Running the binary inside a restricted container or sandbox (Docker with restricted syscall filters, gVisor, seccomp profiles) that blocks pipe2/signal syscalls; processes with exhausted file descriptors so the ctrlc self-pipe cannot be created; embedding the program as a PID-1 process or in environments where signal handlers cannot be registered; uncommon but possible resource exhaustion at startup.
AI-assisted analysis of bootandy/dust@8a846f6689 (2026-09-08).
Data as JSON: /api/errors/dd4f4d03db181177.
Report an issue: GitHub.
Appendix: source
Thrown at src/main.rs:129
process::exit(1)
})
})
.collect()
}
fn main() {
let options = Cli::parse();
let config = get_config(options.config.as_ref());
let errors = RuntimeErrors::default();
let error_listen_for_ctrlc = Arc::new(Mutex::new(errors));
let errors_for_rayon = error_listen_for_ctrlc.clone();
ctrlc::set_handler(move || {
println!("\nAborting");
process::exit(1);
})
.expect("Error setting Ctrl-C handler");
let target_dirs = if let Some(path) = config.get_files0_from(&options) {
read_paths_from_source(&path, true)
} else if let Some(path) = config.get_files_from(&options) {
read_paths_from_source(&path, false)
} else {
match options.params {
Some(ref values) => values.clone(),
None => vec![".".to_owned()],
}
}
.into_iter()
.filter(|path| !path.is_empty())
.collect::<Vec<_>>();
let summarize_file_types = options.file_types;
let filter_regexs = get_regex_value(options.filter.as_ref());View on GitHub (pinned to 8a846f6689)