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

  1. Check pfd.revents for POLLERR/POLLHUP and treat them as end-of-stream (break) instead of attempting reads
  2. On EAGAIN/WouldBlock, continue the loop rather than bailing
  3. 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

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


AI-assisted analysis of wezterm/wezterm@08e5e0afc6 (2026-08-20). Data as JSON: /api/errors/a89bf3840683b08f. Report an issue: GitHub.