facebook/flow · error

Daemon::from_channel: bincode deserialize

Error message

Daemon::from_channel: bincode deserialize

What it means

Panics when bincode cannot decode a message from the daemon's TCP input channel. from_channel wraps try_from_channel in expect, so any DecodeError crashes: Io variants from EOF (peer closed/died mid-message), WouldBlock/TimedOut from the configured read timeout, or InvalidData from garbled bytes. This is the Rust port of the OCaml Flow client<->daemon protocol, where the same failure surfaced as an exception the client loop handled.

Source

Thrown at rust_port/crates/flow_daemon/src/daemon.rs:53

}

pub struct ChannelPair<In, Out>(pub InChannel<In>, pub OutChannel<Out>);

pub struct Handle<In, Out> {
    pub channels: ChannelPair<In, Out>,
    pub child: Child,
}

pub fn to_channel<T: Serialize>(oc: &mut OutChannel<T>, v: &T, should_flush: bool) {
    bincode::serde::encode_into_std_write(v, &mut oc.stream, bincode::config::legacy())
        .expect("Daemon::to_channel: bincode serialize");
    if should_flush {
        oc.stream.flush().expect("Daemon::to_channel: flush failed");
    }
}

pub fn from_channel<T: DeserializeOwned>(ic: &mut InChannel<T>, timeout: Option<Duration>) -> T {
    try_from_channel(ic, timeout).expect("Daemon::from_channel: bincode deserialize")
}

pub fn try_from_channel<T: DeserializeOwned>(
    ic: &mut InChannel<T>,
    timeout: Option<Duration>,
) -> Result<T, bincode::error::DecodeError> {
    ic.stream
        .set_read_timeout(timeout)
        .map_err(|e| bincode::error::DecodeError::Io {
            inner: e,
            additional: 0,
        })?;
    bincode::serde::decode_from_std_read(&mut ic.stream, bincode::config::legacy())
}

pub fn flush<T>(oc: &mut OutChannel<T>) {
    oc.stream.flush().expect("Daemon::flush failed");
}

View on GitHub (pinned to f88ac94bcf)

Solutions

  1. Switch the call site to the public try_from_channel and handle the Result (restart the daemon and retry once) instead of the panicking wrapper
  2. Kill stale daemons from previous versions (delete the daemon socket / pkill the flow daemon process) so a fresh same-version daemon is spawned
  3. Verify the client and daemon are the same binary version (same build/tree) before connecting
  4. Raise or remove the read timeout when the daemon is known to be busy on a long first response

Example fix

// before
let msg = daemon::from_channel(&mut ic, Some(Duration::from_secs(5)));

// after
let msg = match daemon::try_from_channel(&mut ic, Some(Duration::from_secs(5))) {
    Ok(msg) => msg,
    Err(e) => {
        restart_daemon()?;
        daemon::try_from_channel(&mut ic, Some(Duration::from_secs(5)))
            .unwrap_or_else(|e| panic!("daemon unreadable after restart: {e}"))
    }
};
Defensive patterns

Strategy: fallback

Validate before calling

// Prefer the non-panicking variant and restart the daemon on failure
match daemon::try_from_channel(&mut ic, timeout) {
    Ok(msg) => { /* handle message */ }
    Err(e) => { restart_daemon_and_reconnect()?; /* then retry once */ }
}

Try / catch

match daemon::try_from_channel(&mut ic, timeout) {
    Ok(msg) => msg,
    Err(bincode::error::DecodeError::Io { inner, .. })
        if inner.kind() == std::io::ErrorKind::UnexpectedEof
            || inner.kind() == std::io::ErrorKind::ConnectionReset => {
        restart_daemon()?; // peer died mid-message
        daemon::try_from_channel(&mut ic, timeout)?
    }
    Err(e) => return Err(e.into()),
}

Prevention

When it happens

Trigger: Calling from_channel while the flow daemon process has crashed or exited after accepting the connection; passing a timeout shorter than the daemon's response time; running a client and daemon built from different flow versions whose message encodings differ; a TCP connection reset by a proxy, container runtime, or OS.

Common situations: A stale daemon from an older flow binary is still running after an upgrade; the daemon is OOM-killed mid-request; tests use aggressive timeouts; the daemon socket is reached through a dev-container port-forward that drops idle connections.

Related errors


AI-assisted analysis of facebook/flow@f88ac94bcf (2026-08-20). Data as JSON: /api/errors/ec3688bd0813f7d8. Report an issue: GitHub.