fix: prevent daemon panic on broken stderr pipe during Chrome launch (#802)

Replace all `eprintln!` calls in daemon-context code with
`let _ = writeln!(std::io::stderr(), ...)` so that broken pipe errors
on stderr are silently ignored instead of panicking.

The CLI client spawns the daemon with piped stderr to capture startup
errors, then drops the pipe handle once the daemon is ready. Any
subsequent `eprintln!` in the daemon panics because Rust's `eprintln!`
macro internally unwraps the write result. This caused the reported
"failed printing to stderr: Broken pipe (os error 32)" panic during
Chrome launch on Linux.

Closes #799

Co-authored-by: ctate <366502+ctate@users.noreply.github.com>
This commit is contained in:
Chris Tate
2026-03-14 18:08:22 -05:00
committed by GitHub
co-authored by ctate
parent 23a8b19de1
commit c4f0f22ae9
5 changed files with 35 additions and 17 deletions
+15 -9
View File
@@ -1,6 +1,7 @@
use serde_json::Value;
use std::env;
use std::fs;
use std::io::Write;
use std::path::PathBuf;
use std::process;
use std::sync::Arc;
@@ -47,11 +48,12 @@ pub async fn run_daemon(session: &str) {
stream_client = Some(client_slot.clone());
let stream_path = socket_dir.join(format!("{}.stream", session));
if let Err(e) = fs::write(&stream_path, stream_server.port().to_string()) {
eprintln!("Failed to write .stream file: {}", e);
let _ =
writeln!(std::io::stderr(), "Failed to write .stream file: {}", e);
}
}
Err(e) => {
eprintln!("Stream server failed to start: {}", e);
let _ = writeln!(std::io::stderr(), "Stream server failed to start: {}", e);
}
}
}
@@ -73,7 +75,7 @@ pub async fn run_daemon(session: &str) {
let _ = fs::remove_file(&stream_path);
if let Err(e) = result {
eprintln!("Daemon error: {}", e);
let _ = writeln!(std::io::stderr(), "Daemon error: {}", e);
process::exit(1);
}
}
@@ -112,7 +114,7 @@ async fn run_socket_server(
});
}
Err(e) => {
eprintln!("Accept error: {}", e);
let _ = writeln!(std::io::stderr(), "Accept error: {}", e);
}
}
}
@@ -185,7 +187,7 @@ async fn run_socket_server(
});
}
Err(e) => {
eprintln!("Accept error: {}", e);
let _ = writeln!(std::io::stderr(), "Accept error: {}", e);
}
}
}
@@ -299,21 +301,25 @@ async fn shutdown_signal() {
let mut sigint = match signal::unix::signal(signal::unix::SignalKind::interrupt()) {
Ok(s) => s,
Err(e) => {
eprintln!("Failed to install SIGINT handler: {}", e);
let _ = writeln!(std::io::stderr(), "Failed to install SIGINT handler: {}", e);
process::exit(1);
}
};
let mut sigterm = match signal::unix::signal(signal::unix::SignalKind::terminate()) {
Ok(s) => s,
Err(e) => {
eprintln!("Failed to install SIGTERM handler: {}", e);
let _ = writeln!(
std::io::stderr(),
"Failed to install SIGTERM handler: {}",
e
);
process::exit(1);
}
};
let mut sighup = match signal::unix::signal(signal::unix::SignalKind::hangup()) {
Ok(s) => s,
Err(e) => {
eprintln!("Failed to install SIGHUP handler: {}", e);
let _ = writeln!(std::io::stderr(), "Failed to install SIGHUP handler: {}", e);
process::exit(1);
}
};
@@ -328,7 +334,7 @@ async fn shutdown_signal() {
#[cfg(windows)]
{
if let Err(e) = signal::ctrl_c().await {
eprintln!("Failed to install Ctrl+C handler: {}", e);
let _ = writeln!(std::io::stderr(), "Failed to install Ctrl+C handler: {}", e);
process::exit(1);
}
}