{"record":{"id":"2ef305d3e5aef436","repo":"tursodatabase/turso","slug":"error-setting-ctrl-c-handler-2ef305","errorCode":null,"errorMessage":"Error setting Ctrl-C handler","messagePattern":"Error setting Ctrl-C handler","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"postgres/cli/main.rs","lineNumber":1021,"sourceCode":"\nfn main() -> anyhow::Result<()> {\n    let opts = Opts::parse();\n    let _guard = init_tracing(&opts)?;\n\n    let db_file = opts\n        .database\n        .as_ref()\n        .map_or(\":memory:\".to_string(), |p| p.to_string_lossy().to_string());\n\n    let (io, conn) = open_database(&db_file, opts.vfs.as_ref(), opts.readonly)?;\n\n    let interrupt_count = Arc::new(AtomicUsize::new(0));\n    {\n        let ic = Arc::clone(&interrupt_count);\n        ctrlc::set_handler(move || {\n            ic.fetch_add(1, Ordering::Release);\n        })\n        .expect(\"Error setting Ctrl-C handler\");\n    }\n\n    auto_attach_pg_schemas(&conn, &db_file);\n    // Server mode: start PG wire protocol server and exit\n    if let Some(ref address) = opts.server {\n        let server = TursoPgServer::new(address.clone(), db_file, conn, interrupt_count);\n        return server.run();\n    }\n\n    let table_config = TableConfig::adaptive_colors();\n\n    // Execute a single SQL command and exit\n    if let Some(ref sql) = opts.sql {\n        let had_error = execute_sql(&conn, sql, &table_config, false, &mut std::io::stdout());\n        conn.close()?;\n        if had_error {\n            std::process::exit(1);\n        }","sourceCodeStart":1003,"sourceCodeEnd":1039,"githubUrl":"https://github.com/tursodatabase/turso/blob/c1e59287258d99b309e362a63f48822256e2f65f/postgres/cli/main.rs#L1003-L1039","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before: two registrations in one process - second one panics\nctrlc::set_handler(|| println!(\"host\"));\nrun_tursopg_cli(args); // internally calls ctrlc::set_handler again\n\n// after: one handler, fan out manually\nctrlc::set_handler(|| {\n    println!(\"host\");\n    interrupt_tursopg(); // route the signal to the CLI yourself\n});","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"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.","preventionTips":["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."],"tags":["cli","sigint","signal-handler","ctrl-c","embedding","rust","tursopg","panic"],"backgroundTag":"signal-handler-conflict","analyzedSha":"c1e59287258d99b309e362a63f48822256e2f65f","analyzedAt":"2026-08-20T07:02:18.389Z","contentChangedAt":"2026-08-20T07:02:18.389Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}