{"record":{"id":"170c52500b6f03bb","repo":"Hmbown/CodeWhale","slug":"osc-52-clipboard-fallback-requires-a-terminal","errorCode":null,"errorMessage":"OSC 52 clipboard fallback requires a terminal","messagePattern":"OSC 52 clipboard fallback requires a terminal","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/tui/src/tui/clipboard.rs","lineNumber":634,"sourceCode":"\n            #[cfg(target_os = \"windows\")]\n            if write_text_with_set_clipboard(text).is_ok() {\n                return Ok(());\n            }\n\n            self.enqueue_terminal_write(text)\n                .map_err(|err| anyhow::anyhow!(\"Clipboard unavailable: {err}\"))\n        }\n    }\n\n    #[cfg(not(test))]\n    fn enqueue_terminal_write(&mut self, text: &str) -> Result<()> {\n        if !self.terminal_context.in_tmux {\n            if text.len() > OSC52_MAX_BYTES {\n                bail!(\"selection is too large for OSC 52 clipboard fallback\");\n            }\n            if !io::stdout().is_terminal() {\n                bail!(\"OSC 52 clipboard fallback requires a terminal\");\n            }\n        }\n\n        if self.terminal_writer.is_none() {\n            self.terminal_writer = Some(TerminalClipboardWriter::spawn()?);\n        }\n        self.terminal_writer\n            .as_ref()\n            .expect(\"terminal clipboard writer initialized\")\n            .enqueue(text, self.terminal_context.in_tmux)\n    }\n\n    /// Return one completed background terminal clipboard write, if available.\n    ///\n    /// Successes are intentionally quiet because callers already show their\n    /// normal copy receipt. Failures are drained by the event loop and replace\n    /// that optimistic receipt with an actionable error.\n    pub(crate) fn poll_write_completion(&self) -> Option<TerminalClipboardWriteCompletion> {","sourceCodeStart":616,"sourceCodeEnd":652,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/src/tui/clipboard.rs#L616-L652","documentation":"The OSC 52 clipboard fallback works by writing an escape sequence to stdout, which only reaches the terminal's clipboard when stdout is an interactive TTY. `enqueue_terminal_write` checks `io::stdout().is_terminal()` (outside tmux) and fails with this error when stdout is redirected or not a terminal, because the sequence would otherwise be written into a file or pipe.","triggerScenarios":"Calling `write_text` outside tmux when stdout is redirected (e.g. `codewhale ... > log.txt`), piped to another process, or running in an environment with no controlling TTY (CI, daemon, non-interactive SSH without a terminal).","commonSituations":"CI jobs trying to copy to the clipboard; running the tool under a process manager or IDE that captures stdout; remote SSH sessions without `-t`; output redirected to a file.","solutions":["Run in an interactive terminal so stdout is a TTY","Run inside tmux, where this check is skipped and tmux handles clipboard integration","Force a system clipboard helper path (wl-copy/xclip/pbcopy) instead of the OSC 52 terminal fallback","Capture and report the error instead of failing the whole operation when clipboard is best-effort"],"exampleFix":"// before\nlet output = Command::new(\"codewhale\").arg(\"copy\").output()?; // stdout not a TTY\n// after\nlet output = Command::new(\"codewhale\").arg(\"copy\").stdout(Stdio::inherit()).spawn()?; // or run in a TTY","handlingStrategy":"validation","validationCode":"use std::io::IsTerminal;\nif !std::io::stdout().is_terminal() {\n    // skip terminal clipboard write or use a helper-based backend\n}","typeGuard":"fn can_write_osc52() -> bool {\n    use std::io::IsTerminal;\n    std::io::stdout().is_terminal()\n}","tryCatchPattern":"match clipboard.write_text(text) {\n    Err(e) if e.to_string().contains(\"requires a terminal\") => {\n        eprintln!(\"clipboard skipped: no TTY on stdout\");\n    }\n    other => other?,\n}","preventionTips":["Never rely on OSC 52 clipboard writes when stdout may be redirected or piped","Detect non-interactive environments (CI, daemons) and disable terminal clipboard early","Prefer system clipboard helpers in scripted contexts","Run inside tmux where the terminal-TTY requirement is lifted"],"tags":["clipboard","osc52","terminal","stdout","tty"],"backgroundTag":"unsupported-operation","analyzedSha":"73e0f67d83c59909b571efdfc88c4bc28c309cb1","analyzedAt":"2026-09-22T01:30:00.501Z","contentChangedAt":"2026-09-22T01:30:00.501Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}