facebook/flow · error · std::io::Error
socket timeout
Error message
socket timeout
What it means
wait_ready wraps a socket readiness future (connect or read/write readiness) in tokio::time::timeout inside block_on, honoring the timeout the caller set via SocketStream::set_read_timeout / set_write_timeout. If the underlying operation does not become ready within that duration, it returns ErrorKind::TimedOut "socket timeout" — the peer neither progressed nor closed within your deadline.
Source
Thrown at rust_port/crates/flow_common_socket/src/socket.rs:401
}
}
#[cfg(windows)]
fn wait_for_ready(
timeout: Option<Duration>,
ready: impl std::future::Future<Output = io::Result<()>>,
) -> io::Result<()> {
match timeout {
None => flow_tokio_runtime::block_on(ready),
Some(timeout) => {
// `tokio::time::timeout` constructs a `Sleep` that registers with
// the reactor at construction time, so it must be created inside
// the runtime context, not before `block_on`.
match flow_tokio_runtime::block_on(
async move { tokio::time::timeout(timeout, ready).await },
) {
Ok(result) => result,
Err(_) => Err(io::Error::new(io::ErrorKind::TimedOut, "socket timeout")),
}
}
}
}
impl Read for SocketStream {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
if buf.is_empty() {
return Ok(0);
}
#[cfg(unix)]
{
self.socket.read(buf)
}
#[cfg(windows)]
{
loop {
let result = match &*self.pipe {View on GitHub (pinned to f88ac94bcf)
Solutions
- Raise the read/write timeout to comfortably cover the slowest legitimate request (large project checks can take seconds).
- Check the server's health (logs, CPU, whether it is stopped under a debugger) — a silent-but-open peer is usually a hung server.
- Retry the request on a fresh connection; Flow client queries are idempotent, so re-issuing after a timeout is safe.
- If the operation legitimately exceeds the timeout, shrink the payload or split the query.
Example fix
// before: tuned for instant local replies stream.set_read_timeout(Some(Duration::from_millis(100)))?; // after: budget for large queries and loaded machines stream.set_read_timeout(Some(Duration::from_secs(30)))?;
Defensive patterns
Strategy: retry
Type guard
fn is_socket_timeout(e: &std::io::Error) -> bool {
e.kind() == std::io::ErrorKind::TimedOut && e.to_string().contains("socket timeout")
} Try / catch
Match ErrorKind::TimedOut on stream ops: re-issue the request once on a fresh connection (Flow queries are idempotent), then surface 'server unresponsive' if it repeats. Other error kinds (UnexpectedEof, BrokenPipe) mean the connection died — reconnect without retrying blindly.
Prevention
- Set read/write timeouts to at least several times your p99 request duration.
- Watch server health (heartbeat/log activity) and reconnect on repeated timeouts.
- Make callers timeout-aware: treat TimedOut as retryable, not as a data error.
When it happens
Trigger: A read or write on a SocketStream after set_read_timeout/set_write_timeout(Some(d)) where the server sends nothing and keeps the connection open longer than d; or a connect/readiness wait exceeding the configured timeout.
Common situations: A hung or SIGSTOP-ed Flow server that leaves the socket open but never replies; a very large query legitimately slower than a locally-tuned timeout; loaded CI machines turning normally-fast requests into timeouts.
Understand the failure class
- Timeouts: ETIMEDOUT, deadlines, and hung requests — what actually expires when a request times out.
Related errors
- timed out connecting to named pipe
- Daemon::spawn: timed out waiting for child to connect
- Daemon::spawn: timed out reading token from child
- Daemon::from_channel: bincode deserialize
- Unknown exception reading from the server: {}
AI-assisted analysis of facebook/flow@f88ac94bcf (2026-08-20).
Data as JSON: /api/errors/f0416a4d6acb6943.
Report an issue: GitHub.