{"record":{"id":"b0689240a4f0643c","repo":"Hmbown/CodeWhale","slug":"failed-to-write-to-program-e","errorCode":null,"errorMessage":"Failed to write to {program}: {e}","messagePattern":"Failed to write to (.+?): (.+?)","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/tui/src/tui/clipboard.rs","lineNumber":588,"sourceCode":"        .map_err(|e| anyhow::anyhow!(\"Failed to run {program}: {e}\"))?;\n    if !output.status.success() {\n        bail!(\"{program} exited with {}\", output.status);\n    }\n    String::from_utf8(output.stdout).context(\"wl-paste returned non-UTF-8 text\")\n}\n\n#[cfg(all(target_os = \"linux\", not(target_env = \"ohos\"), not(test)))]\nfn write_text_with_wlcopy_using_argv(program: &str, text: &str) -> Result<()> {\n    let mut child = Command::new(program)\n        .stdin(Stdio::piped())\n        .stdout(Stdio::null())\n        .stderr(Stdio::null())\n        .spawn()\n        .map_err(|e| anyhow::anyhow!(\"Failed to run {program}: {e}\"))?;\n    if let Some(mut stdin) = child.stdin.take() {\n        stdin\n            .write_all(text.as_bytes())\n            .map_err(|e| anyhow::anyhow!(\"Failed to write to {program}: {e}\"))?;\n    }\n    // stdin is dropped here, closing the pipe so wl-copy flushes.\n    let status = child\n        .wait()\n        .map_err(|e| anyhow::anyhow!(\"Failed to wait on {program}: {e}\"))?;\n    if !status.success() {\n        bail!(\"{program} exited with {status}\");\n    }\n    Ok(())\n}\n\n#[cfg(not(test))]\nfn write_text_to_terminal_client(text: &str, in_tmux: bool) -> Result<()> {\n    if in_tmux {\n        return write_text_with_tmux(text);\n    }\n    write_text_with_osc52(text)\n}","sourceCodeStart":570,"sourceCodeEnd":606,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/0c42157ee52f9d55af2b506d71b46249910f77d3/crates/tui/src/tui/clipboard.rs#L570-L606","documentation":"write_all to wl-copy's piped stdin failed. Nearly always EPIPE: wl-copy spawned but exited immediately (no reachable Wayland compositor, stale WAYLAND_DISPLAY, clipboard daemon error), closing the pipe before the payload was written. Distinct from wl-copy's own non-zero exit, which is reported separately after wait().","triggerScenarios":"wl-copy exits at startup because WAYLAND_DISPLAY points at a dead compositor socket or the session bus is unavailable; stdin.write_all then returns BrokenPipe.","commonSituations":"SSH sessions inheriting a stale WAYLAND_DISPLAY; compositor crash; running wl-copy on X11-only systems.","solutions":["Verify a live Wayland session in the same shell: `echo $WAYLAND_DISPLAY` then `echo hi | wl-copy`","unset WAYLAND_DISPLAY if the session is not actually Wayland so the OSC 52 fallback wins cleanly","Restart the compositor/session when the socket is stale"],"exampleFix":"# before\nexport WAYLAND_DISPLAY=wayland-0   # stale, compositor gone\ncodewhale tui                        # copy -> Failed to write to wl-copy: broken pipe\n\n# after\nunset WAYLAND_DISPLAY\ncodewhale tui                        # falls back to OSC 52 / tmux","handlingStrategy":"fallback","validationCode":"// Rust - probe the Wayland clipboard socket liveness cheaply before large writes\nfn wayland_session_alive() -> bool {\n    std::env::var(\"WAYLAND_DISPLAY\").map(|d| {\n        let runtime = std::env::var(\"XDG_RUNTIME_DIR\").unwrap_or_default();\n        !runtime.is_empty() && std::path::Path::new(&runtime).join(&d).exists()\n    }).unwrap_or(false)\n}","typeGuard":null,"tryCatchPattern":"match write_text_with_wlcopy(text) {\n    Err(e) if e.chain().any(|c| c.to_string().contains(\"broken pipe\")) => {\n        unset_env_and_use_osc52(); // compositor gone: fall through, never retry wl-copy\n    }\n    r => r,\n}","preventionTips":["Validate WAYLAND_DISPLAY points at a live socket after SSH/compositor changes","Treat EPIPE from clipboard helpers as 'transport refused', not a transient error","Chain transports so a dead compositor degrades to OSC 52/tmux automatically"],"tags":["clipboard","broken-pipe","wl-clipboard","wayland"],"backgroundTag":"broken-pipe","analyzedSha":"0c42157ee52f9d55af2b506d71b46249910f77d3","analyzedAt":"2026-08-20T21:50:45.477Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}