{"record":{"id":"7ac01ff2c6a936d9","repo":"facebook/flow","slug":"clone-of-socket-stream-for-read-failed","errorCode":null,"errorMessage":"clone of socket stream for read failed","messagePattern":"clone of socket stream for read failed","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"rust_port/crates/flow_server_monitor/src/socket_acceptor.rs","lineNumber":121,"sourceCode":"        conn: &Self::Connection,\n    ) -> bool {\n        conn.write(\n            flow_server_env::lsp_prot::MessageFromServer::NotificationFromServer(\n                flow_server_env::lsp_prot::NotificationFromServer::PleaseHold(status.0, status.1),\n            ),\n        )\n    }\n}\n\nfn create_ephemeral_connection(\n    client_stream: SocketStream,\n    close: Arc<dyn Fn() + Send + Sync>,\n) -> Arc<crate::flow_server_monitor_connection::EphemeralConnection> {\n    flow_hh_logger::debug!(\"Creating a new ephemeral connection\");\n\n    let read_stream = client_stream\n        .try_clone()\n        .expect(\"clone of socket stream for read failed\");\n    let write_stream = client_stream;\n\n    let close_for_create = close.clone();\n    let (start, conn) = crate::flow_server_monitor_connection::EphemeralConnection::create(\n        \"some ephemeral connection\".to_string(),\n        read_stream,\n        write_stream,\n        move || close_for_create(),\n        |msg, connection| {\n            handle_ephemeral_request(msg, connection.clone());\n        },\n    );\n\n    // On exit, do our best to send all pending messages to the waiting client.\n    let conn_for_close_on_exit = conn.clone();\n    let close_on_exit = async move {\n        crate::exit_signal::SIGNAL.notified().await;\n        tokio::task::spawn_blocking(move || {","sourceCodeStart":103,"sourceCodeEnd":139,"githubUrl":"https://github.com/facebook/flow/blob/f88ac94bcf6992f5d5a158854d94613ebb92c6e6/rust_port/crates/flow_server_monitor/src/socket_acceptor.rs#L103-L139","documentation":"When the monitor's socket acceptor receives a client, create_ephemeral_connection clones the client SocketStream so one handle reads while the original writes: client_stream.try_clone().expect(\"clone of socket stream for read failed\") (rust_port/crates/flow_server_monitor/src/socket_acceptor.rs:118-121). try_clone duplicates the fd; on failure (EMFILE at the fd ceiling, or the peer already reset the connection) the acceptor thread panics, dropping service for all monitor clients.","triggerScenarios":"A new monitor client connecting when the monitor is at RLIMIT_NOFILE — each ephemeral connection consumes extra fds (the stream plus its clone) — or a client that connects and immediately RSTs so the clone errors.","commonSituations":"Many editors or CLI tools connecting through the monitor socket concurrently; fd leaks accumulating over long monitor uptime; containers with the default 1024 fd limit.","solutions":["Raise ulimit -n for the monitor process (LimitNOFILE for systemd, --ulimit nofile= for Docker)","Confirm exhaustion live: ls /proc/<monitor-pid>/fd | wc -l while clients connect","Reduce the number of concurrent monitor clients","Upstream: treat clone failure as a per-connection error (log and drop that client) instead of a panic in the acceptor"],"exampleFix":"// before\nlet read_stream = client_stream\n    .try_clone()\n    .expect(\"clone of socket stream for read failed\");\n\n// after: a per-client failure no longer kills the acceptor\nlet Some(read_stream) = client_stream.try_clone().ok() else {\n    eprintln!(\"Error cloning client stream; dropping this connection\");\n    close();\n    return None;\n};","handlingStrategy":"validation","validationCode":"// Acceptor-level fd guard before cloning the client stream\nlet open = std::fs::read_dir(\"/proc/self/fd\").map(|d| d.count()).unwrap_or(0);\nif open + 4 >= fd_limit() {\n    eprintln!(\"Refusing monitor client: fd budget nearly exhausted ({open})\");\n    drop(client_stream);\n    return None;\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Raise ulimit -n for the monitor above 1024 defaults","Cap concurrent monitor clients","Alert on open-fd growth over time to catch leaks before the acceptor dies"],"tags":["monitor","try-clone","fd-exhaustion","socket-accept","panic"],"backgroundTag":"fd-exhaustion","analyzedSha":"f88ac94bcf6992f5d5a158854d94613ebb92c6e6","analyzedAt":"2026-08-20T10:41:37.992Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}