wezterm/wezterm · warning
error reading from pipe: {}
Error message
error reading from pipe: {} What it means
read_pipe_with_timeout's loop got an Err from read(2) after poll(2) reported the fd readable. The errno is in the message: usually EAGAIN (poll woke on POLLERR/POLLHUP or the data was consumed elsewhere — the code only checks the ready count, not pfd.revents) or EIO when the writer side (compositor/source) killed the pipe.
Source
Thrown at window/src/os/wayland/window.rs:574
let mut pfd = libc::pollfd {
fd: file.as_raw_fd(),
events: libc::POLLIN,
revents: 0,
};
let mut buf = [0u8; 8192];
loop {
if unsafe { libc::poll(&mut pfd, 1, 3000) == 1 } {
match file.read(&mut buf) {
Ok(size) if size == 0 => {
break;
}
Ok(size) => {
result.extend_from_slice(&buf[..size]);
}
Err(e) => bail!("error reading from pipe: {}", e),
}
} else {
bail!("timed out reading from pipe");
}
}
Ok(String::from_utf8(result)?)
}
pub struct WaylandWindowInner {
pub(crate) events: WindowEventSender,
surface_factor: f64,
window: Option<XdgWindow>,
pub(super) window_frame: FallbackFrame<WaylandState>,
dimensions: Dimensions,
resize_increments: Option<ResizeIncrement>,
window_state: WindowState,
last_mouse_coords: Point,View on GitHub (pinned to 08e5e0afc6)
Solutions
- Check pfd.revents for POLLERR/POLLHUP and treat them as end-of-stream (break) instead of attempting reads
- On EAGAIN/WouldBlock, continue the loop rather than bailing
- Treat remaining EIO as 'selection source died' and fall back to an empty result
Example fix
// before
Err(e) => bail!("error reading from pipe: {}", e),
// after
Err(e) if e.kind() == std::io::ErrorKind::WouldBlock => continue,
Err(e) => bail!("error reading from pipe: {}", e),
// and after poll: if pfd.revents & (libc::POLLERR | libc::POLLHUP) != 0 { break; } Defensive patterns
Strategy: fallback
Validate before calling
// After poll, classify the wakeup before reading
if pfd.revents & (libc::POLLERR | libc::POLLHUP) != 0 {
// writer is gone: end of stream, not an error
} Try / catch
match file.read(&mut buf) {
Ok(0) => break,
Ok(n) => result.extend_from_slice(&buf[..n]),
Err(e) if e.kind() == std::io::ErrorKind::WouldBlock => continue,
Err(e) if e.kind() == std::io::ErrorKind::BrokenPipe => break,
Err(e) => bail!("error reading from pipe: {e}"),
} Prevention
- Check revents bits (POLLERR/POLLHUP) rather than trusting the poll ready count
- Retry on WouldBlock: spurious poll wakeups are normal for pipes
- Treat mid-transfer reader errors as empty-selection outcomes in UI code
When it happens
Trigger: Peer closed the pipe while the reader was mid-loop (POLLHUP race); poll spurious wakeup with nothing readable; fd invalidated by concurrent offer teardown.
Common situations: Reading a selection whose source exits mid-transfer; compositor closing the pipe after offer replacement; concurrent readers on the same fd.
Related errors
- timed out writing to pipe
- timed out reading from pipe
- failed to change non-blocking mode: {}
- zero byte write
- error writing to pipe: {}
AI-assisted analysis of wezterm/wezterm@08e5e0afc6 (2026-08-20).
Data as JSON: /api/errors/a89bf3840683b08f.
Report an issue: GitHub.