{"record":{"id":"a89bf3840683b08f","repo":"wezterm/wezterm","slug":"error-reading-from-pipe","errorCode":null,"errorMessage":"error reading from pipe: {}","messagePattern":"error reading from pipe: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"window/src/os/wayland/window.rs","lineNumber":574,"sourceCode":"\n    let mut pfd = libc::pollfd {\n        fd: file.as_raw_fd(),\n        events: libc::POLLIN,\n        revents: 0,\n    };\n\n    let mut buf = [0u8; 8192];\n\n    loop {\n        if unsafe { libc::poll(&mut pfd, 1, 3000) == 1 } {\n            match file.read(&mut buf) {\n                Ok(size) if size == 0 => {\n                    break;\n                }\n                Ok(size) => {\n                    result.extend_from_slice(&buf[..size]);\n                }\n                Err(e) => bail!(\"error reading from pipe: {}\", e),\n            }\n        } else {\n            bail!(\"timed out reading from pipe\");\n        }\n    }\n\n    Ok(String::from_utf8(result)?)\n}\n\npub struct WaylandWindowInner {\n    pub(crate) events: WindowEventSender,\n    surface_factor: f64,\n    window: Option<XdgWindow>,\n    pub(super) window_frame: FallbackFrame<WaylandState>,\n    dimensions: Dimensions,\n    resize_increments: Option<ResizeIncrement>,\n    window_state: WindowState,\n    last_mouse_coords: Point,","sourceCodeStart":556,"sourceCodeEnd":592,"githubUrl":"https://github.com/wezterm/wezterm/blob/08e5e0afc6007567d3d131bc2ec1382423c0d2da/window/src/os/wayland/window.rs#L556-L592","documentation":"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.","triggerScenarios":"Peer closed the pipe while the reader was mid-loop (POLLHUP race); poll spurious wakeup with nothing readable; fd invalidated by concurrent offer teardown.","commonSituations":"Reading a selection whose source exits mid-transfer; compositor closing the pipe after offer replacement; concurrent readers on the same fd.","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"],"exampleFix":"// before\nErr(e) => bail!(\"error reading from pipe: {}\", e),\n\n// after\nErr(e) if e.kind() == std::io::ErrorKind::WouldBlock => continue,\nErr(e) => bail!(\"error reading from pipe: {}\", e),\n// and after poll: if pfd.revents & (libc::POLLERR | libc::POLLHUP) != 0 { break; }","handlingStrategy":"fallback","validationCode":"// After poll, classify the wakeup before reading\nif pfd.revents & (libc::POLLERR | libc::POLLHUP) != 0 {\n    // writer is gone: end of stream, not an error\n}","typeGuard":null,"tryCatchPattern":"match file.read(&mut buf) {\n    Ok(0) => break,\n    Ok(n) => result.extend_from_slice(&buf[..n]),\n    Err(e) if e.kind() == std::io::ErrorKind::WouldBlock => continue,\n    Err(e) if e.kind() == std::io::ErrorKind::BrokenPipe => break,\n    Err(e) => bail!(\"error reading from pipe: {e}\"),\n}","preventionTips":["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"],"tags":["wayland","clipboard","pipe","read","poll"],"backgroundTag":"broken-pipe","analyzedSha":"08e5e0afc6007567d3d131bc2ec1382423c0d2da","analyzedAt":"2026-08-20T04:47:31.434Z","contentChangedAt":"2026-08-20T04:47:31.434Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}