facebook/flow · critical
Monitor_died (EPIPE)
Error message
Monitor_died (EPIPE)
What it means
The Flow server pushes ServerToMonitorMessage frames (status updates, responses) to its monitor process over a pipe, and send() writes synchronously. If the write fails with ErrorKind::BrokenPipe, the monitor's read end is gone, and the code panics with 'Monitor_died (EPIPE)' — deliberately killing the server, because a server that lost its monitor cannot be supervised. Other write errors are only logged, so this panic specifically means the peer closed the pipe.
Source
Thrown at rust_port/crates/flow_monitor_rpc/src/monitor_rpc.rs:160
writer.write_all(&len.to_be_bytes())?;
writer.write_all(&json)?;
writer.flush()
}
// Sends a message to the monitor.
//
// This is a no-op if the MonitorRPC is disabled. This allows the server to stream things like
// status updates without worrying whether or not there is a monitor
//
// Unliked read, this is synchronous. We don't currently have a use case for async sends, and it's a
// little painful to thread lwt through to everywhere we send data
fn send(msg: monitor_prot::ServerToMonitorMessage) {
with_outfd(
|| {},
|outfd| {
if let Err(e) = flow_parser::loc::with_full_source_serde(|| send_message(outfd, &msg)) {
if e.kind() == io::ErrorKind::BrokenPipe {
panic!("Monitor_died (EPIPE)");
} else {
log::error!("MonitorRPC.send: write failed: {}", e);
}
}
},
);
}
// Respond to a request from an ephemeral client
pub fn respond_to_request(request_id: monitor_prot::RequestId, response: response::Response) {
send(monitor_prot::ServerToMonitorMessage::Response(
request_id, response,
));
}
// Exception while handling the request
pub fn request_failed(request_id: monitor_prot::RequestId, exn_str: String) {
send(monitor_prot::ServerToMonitorMessage::RequestFailed(View on GitHub (pinned to f88ac94bcf)
Solutions
- Treat it as a shutdown signal, not a bug to patch around: restart the pair (flow stop then start, or reconnect the IDE) so a fresh server and monitor come up together.
- Find why the monitor died first: monitor logs, dmesg for OOM, and whether the monitor exited on an unrecognized frame.
- If it recurs at startup, make sure monitor and server binaries come from the same Flow installation/version.
- Never kill only one of the two processes; use the supported stop command so both shut down cleanly.
Example fix
# before: killing only the monitor guarantees a later EPIPE panic in the server pkill -f flow-server-monitor # after: stop the pair through the supported entry point flow stop
Defensive patterns
Strategy: fallback
Try / catch
use std::panic::{catch_unwind, AssertUnwindSafe};
let result = catch_unwind(AssertUnwindSafe(|| run_server_main()));
if result.is_err() {
// 'Monitor_died (EPIPE)': the monitor is gone by design.
// Fall back to supervised shutdown instead of letting the abort leak.
supervisor::restart_monitor_and_server_pair();
} Prevention
- Always stop monitor and server together via the supported stop command; never pkill only one.
- Run the pair under one supervisor (systemd/launchd unit) that restarts them as a unit.
- Keep monitor and server binaries from the same Flow installation so neither exits on unrecognized frames.
- Check dmesg for OOM kills on the monitor when this recurs.
When it happens
Trigger: The monitor process (flow-server-monitor, e.g. under an IDE integration) crashes, is killed, or exits normally while the server is still streaming: the very next send() from the server hits EPIPE and panics. Happens on status broadcasts as easily as on request responses.
Common situations: IDE extension updated or restarted while an old flow server daemon from the previous session kept running; the monitor OOM-killed (check dmesg); users pkill-ing only the monitor; monitor/server version skew where the monitor exits early on an unrecognized message.
Related errors
- Daemon::to_channel: bincode serialize
- Daemon::to_channel: flush failed
- Daemon child: failed to write token to parent out-socket: {}
- Daemon child: failed to write token to parent in-socket: {}
- failed to spawn server daemon: {}
AI-assisted analysis of facebook/flow@f88ac94bcf (2026-08-20).
Data as JSON: /api/errors/2e91e95b81876e0a.
Report an issue: GitHub.