{"record":{"id":"8746e006d8874c4d","repo":"facebook/flow","slug":"daemon-flush-failed","errorCode":null,"errorMessage":"Daemon::flush failed","messagePattern":"Daemon::flush failed","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"rust_port/crates/flow_daemon/src/daemon.rs","lineNumber":70,"sourceCode":"pub fn from_channel<T: DeserializeOwned>(ic: &mut InChannel<T>, timeout: Option<Duration>) -> T {\n    try_from_channel(ic, timeout).expect(\"Daemon::from_channel: bincode deserialize\")\n}\n\npub fn try_from_channel<T: DeserializeOwned>(\n    ic: &mut InChannel<T>,\n    timeout: Option<Duration>,\n) -> Result<T, bincode::error::DecodeError> {\n    ic.stream\n        .set_read_timeout(timeout)\n        .map_err(|e| bincode::error::DecodeError::Io {\n            inner: e,\n            additional: 0,\n        })?;\n    bincode::serde::decode_from_std_read(&mut ic.stream, bincode::config::legacy())\n}\n\npub fn flush<T>(oc: &mut OutChannel<T>) {\n    oc.stream.flush().expect(\"Daemon::flush failed\");\n}\n\n// OCaml's `Unix.file_descr` is uniformly an int (or HANDLE on Windows),\n// allowing it to refer to either a file or a socket. Rust has no such\n// uniform type that is also cross-platform, so for `InChannel`/`OutChannel`\n// (which are always TCP sockets in this port) we expose the underlying\n// `TcpStream` directly. Callers that need an independent handle can call\n// `try_clone()` on the returned reference -- this works on both Unix and\n// Windows, unlike `BorrowedFd`/`nix::unistd::dup` which are Unix-only.\npub fn descr_of_in_channel<T>(ic: &InChannel<T>) -> &TcpStream {\n    &ic.stream\n}\n\npub fn descr_of_out_channel<T>(oc: &OutChannel<T>) -> &TcpStream {\n    &oc.stream\n}\n\npub fn into_out_writer<T>(oc: OutChannel<T>) -> Box<dyn std::io::Write + Send> {","sourceCodeStart":52,"sourceCodeEnd":88,"githubUrl":"https://github.com/facebook/flow/blob/f88ac94bcf6992f5d5a158854d94613ebb92c6e6/rust_port/crates/flow_daemon/src/daemon.rs#L52-L88","documentation":"Panics when flushing the daemon output channel's underlying stream fails. The comment in this port notes InChannel/OutChannel always wrap TcpStream, and std's TcpStream::flush is effectively a no-op that returns Ok, so in practice this site is only reachable through an OS-reported I/O error or a wrapped writer. The OCaml original raised on write/flush errors of the channel the same way.","triggerScenarios":"Calling daemon::flush on a channel whose socket already has a pending error reported by the OS (connection reset by peer, EPIPE); the peer closed the connection between the last write and the flush; a custom/wrapped writer with a real flush implementation that errors.","commonSituations":"Daemon process exits between message write and flush; connection torn down by a firewall or container proxy; extremely rare on plain TCP sockets since std flush does not transmit anything.","solutions":["Check the peer/connection is still alive before flushing (take_error on the TcpStream) and reconnect if not","Confirm nothing wraps or replaces the OutChannel stream type with a writer whose flush can fail","Treat a flush panic as a symptom of the peer dying: restart the daemon and re-establish channels"],"exampleFix":"// before\ndaemon::flush(&mut oc);\n\n// after — surface the pending socket error instead of panicking\nif let Some(err) = oc.stream.take_error().ok().flatten() {\n    return Err(anyhow::anyhow!(\"daemon socket error before flush: {err}\"));\n}\ndaemon::flush(&mut oc);","handlingStrategy":"validation","validationCode":"// Surface a pending socket error before flushing\nif let Some(err) = oc.stream.take_error().ok().flatten() {\n    return Err(anyhow::anyhow!(\"daemon socket error: {err}\"));\n}\ndaemon::flush(&mut oc);","typeGuard":null,"tryCatchPattern":"let _ = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| daemon::flush(&mut oc)));\n// A flush panic means the channel is dead: tear it down and reconnect.","preventionTips":["Treat any write/flush panic on the daemon channel as a dead connection and re-establish it","Do not wrap OutChannel's stream in writers whose flush can fail","Handle peer-exit (SIGCHLD / connection reset) before issuing more writes"],"tags":["rust","tcp","flush","io","daemon"],"backgroundTag":"broken-pipe","analyzedSha":"f88ac94bcf6992f5d5a158854d94613ebb92c6e6","analyzedAt":"2026-08-20T10:41:37.992Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}