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

  1. Raise the read/write timeout to comfortably cover the slowest legitimate request (large project checks can take seconds).
  2. Check the server's health (logs, CPU, whether it is stopped under a debugger) — a silent-but-open peer is usually a hung server.
  3. Retry the request on a fresh connection; Flow client queries are idempotent, so re-issuing after a timeout is safe.
  4. 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

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

Related errors


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