tursodatabase/turso · error
Error setting Ctrl-C handler
Error message
Error setting Ctrl-C handler
What it means
On startup the tursopg CLI registers a Ctrl-C handler with ctrlc::set_handler that increments an AtomicUsize interrupt counter (postgres/cli/main.rs:1007-1011) and unwraps the result with expect("Error setting Ctrl-C handler"). ctrlc::set_handler fails when another SIGINT/SIGTERM handler is already installed in the process (the crate permits exactly one) or when the platform's signal mechanism cannot be initialized - and the expect turns that into a process abort.
Source
Thrown at postgres/cli/main.rs:1021
fn main() -> anyhow::Result<()> {
let opts = Opts::parse();
let _guard = init_tracing(&opts)?;
let db_file = opts
.database
.as_ref()
.map_or(":memory:".to_string(), |p| p.to_string_lossy().to_string());
let (io, conn) = open_database(&db_file, opts.vfs.as_ref(), opts.readonly)?;
let interrupt_count = Arc::new(AtomicUsize::new(0));
{
let ic = Arc::clone(&interrupt_count);
ctrlc::set_handler(move || {
ic.fetch_add(1, Ordering::Release);
})
.expect("Error setting Ctrl-C handler");
}
auto_attach_pg_schemas(&conn, &db_file);
// Server mode: start PG wire protocol server and exit
if let Some(ref address) = opts.server {
let server = TursoPgServer::new(address.clone(), db_file, conn, interrupt_count);
return server.run();
}
let table_config = TableConfig::adaptive_colors();
// Execute a single SQL command and exit
if let Some(ref sql) = opts.sql {
let had_error = execute_sql(&conn, sql, &table_config, false, &mut std::io::stdout());
conn.close()?;
if had_error {
std::process::exit(1);
}View on GitHub (pinned to c1e5928725)
Solutions
- Run tursopg as its own process (subprocess) instead of embedding it in a host that owns signal handling.
- If you control the host, register exactly one Ctrl-C handler for the whole process and fan the event out to tursopg and other consumers yourself.
- Remove or defer competing signal registrations before tursopg starts.
- Report an issue requesting graceful degradation: log-and-continue without Ctrl-C support instead of panicking.
Example fix
// before: two registrations in one process - second one panics
ctrlc::set_handler(|| println!("host"));
run_tursopg_cli(args); // internally calls ctrlc::set_handler again
// after: one handler, fan out manually
ctrlc::set_handler(|| {
println!("host");
interrupt_tursopg(); // route the signal to the CLI yourself
}); Defensive patterns
Strategy: try-catch
Try / catch
If embedding: never rely on the CLI's own registration; own the single handler yourself and forward interrupts. Rust hosts can also std::panic::catch_unwind(AssertUnwindSafe(|| run_cli(args))) to convert the startup panic into an error and re-run tursopg as a subprocess instead.
Prevention
- One Ctrl-C handler per process - decide which layer owns it before adding signal code.
- Run tursopg as a subprocess when the host already handles signals.
- In test harnesses, register the harness handler before anything that might install its own.
- Audit embedded CLI invocations for double signal registration after upgrades.
When it happens
Trigger: Embedding or invoking the tursopg CLI code inside a process that already registered signal handling - a prior ctrlc::set_handler call, tokio::signal, JVM/Python interpreter handlers - or a second registration attempt in the same process; also signal-restricted environments where handler installation fails.
Common situations: Test harnesses that install their own interrupt handling before driving the CLI, host applications embedding tursopg as a library, running under certain debuggers or sanitizers that interfere with signal setup.
Related errors
- Could not determine home directory
- Unexpected row for INSERT
- Failed to read manual page: {}
- Manual page not found: {page_name}
- failed to generate random bytes
AI-assisted analysis of tursodatabase/turso@c1e5928725 (2026-08-20).
Data as JSON: /api/errors/2ef305d3e5aef436.
Report an issue: GitHub.