{"record":{"id":"6ba5b8302fa237f5","repo":"facebook/flow","slug":"daemon-to-channel-bincode-serialize","errorCode":null,"errorMessage":"Daemon::to_channel: bincode serialize","messagePattern":"Daemon::to_channel: bincode serialize","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"rust_port/crates/flow_daemon/src/daemon.rs","lineNumber":46,"sourceCode":"    _phantom: PhantomData<fn() -> T>,\n}\n\n// type 'a out_channel = Stdlib.out_channel\npub struct OutChannel<T> {\n    stream: TcpStream,\n    _phantom: PhantomData<fn(T)>,\n}\n\npub struct ChannelPair<In, Out>(pub InChannel<In>, pub OutChannel<Out>);\n\npub struct Handle<In, Out> {\n    pub channels: ChannelPair<In, Out>,\n    pub child: Child,\n}\n\npub fn to_channel<T: Serialize>(oc: &mut OutChannel<T>, v: &T, should_flush: bool) {\n    bincode::serde::encode_into_std_write(v, &mut oc.stream, bincode::config::legacy())\n        .expect(\"Daemon::to_channel: bincode serialize\");\n    if should_flush {\n        oc.stream.flush().expect(\"Daemon::to_channel: flush failed\");\n    }\n}\n\npub 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,","sourceCodeStart":28,"sourceCodeEnd":64,"githubUrl":"https://github.com/facebook/flow/blob/f88ac94bcf6992f5d5a158854d94613ebb92c6e6/rust_port/crates/flow_daemon/src/daemon.rs#L28-L64","documentation":"`Daemon::to_channel` bincode-encodes a message into the daemon child's pipe with `encode_into_std_write(...).expect(\"Daemon::to_channel: bincode serialize\")`. Serialization of these message types is effectively infallible, so a failure here is an IO error on the underlying stream — almost always EPIPE because the child process died or closed its end of the pipe mid-protocol.","triggerScenarios":"The daemon child crashed, was OOM-killed, or exited before reading the next message; a protocol/version mismatch making the child exit on the first malformed-to-it message; external tooling killing the child; the child closing stdin deliberately.","commonSituations":"Long-running parent/child sessions where the child hits a panic or resource limit; partial upgrades leaving parent and child speaking different bincode layouts; sandboxes reaping background children.","solutions":["Check the child when the channel errors (`handle.child.try_wait()`) and restart the daemon, then resend.","Ensure parent and child binaries come from the same build so the bincode `legacy()` layout matches on both ends.","Inspect the child's logs/stderr for the underlying crash and fix that root cause.","Code fix: return an error (e.g., `io::Result<()>`) from to_channel and map BrokenPipe to a child-restart path instead of expect."],"exampleFix":"// before\nbincode::serde::encode_into_std_write(v, &mut oc.stream, bincode::config::legacy())\n    .expect(\"Daemon::to_channel: bincode serialize\");\n\n// after\npub fn to_channel<T: Serialize>(oc: &mut OutChannel<T>, v: &T, should_flush: bool) -> std::io::Result<()> {\n    bincode::serde::encode_into_std_write(v, &mut oc.stream, bincode::config::legacy())?;\n    if should_flush { oc.stream.flush()?; }\n    Ok(())\n} // caller: on ErrorKind::BrokenPipe, reap child, respawn daemon, resend","handlingStrategy":"try-catch","validationCode":"// Before sending, confirm the child is still alive\nfn child_alive(child: &mut std::process::Child) -> bool {\n    matches!(child.try_wait(), Ok(None))\n}","typeGuard":null,"tryCatchPattern":"if let Err(e) = bincode::serde::encode_into_std_write(v, &mut oc.stream, bincode::config::legacy()) {\n    if e.kind() == std::io::ErrorKind::BrokenPipe || e.kind() == std::io::ErrorKind::UnexpectedEof {\n        // child is gone: reap, respawn the daemon, resend the message\n    }\n}","preventionTips":["Deploy parent and child binaries together so bincode layouts always match.","Monitor daemon child liveness (try_wait) and restart on death instead of writing into a dead pipe.","Capture the child's stderr to a file so the root-cause crash is diagnosable."],"tags":["daemon","bincode","ipc","broken-pipe"],"backgroundTag":"broken-pipe","analyzedSha":"f88ac94bcf6992f5d5a158854d94613ebb92c6e6","analyzedAt":"2026-08-20T10:41:37.992Z","schemaVersion":2},"datasetVersion":"2026-08-23T13:05:23.226Z"}