Hmbown/CodeWhale · error

terminal clipboard writer stopped

Error message

terminal clipboard writer stopped

What it means

The terminal clipboard writer's background thread has exited, dropping its side of the std::sync::mpsc channel, so a new clipboard write request cannot be queued. enqueue() surfaces the Disconnected variant of try_send as this error to distinguish a dead writer from a merely busy one.

Solutions

  1. Recreate or reinitialize the terminal clipboard backend/writer thread before retrying the write
  2. Fall back to a direct clipboard write path (wlcopy / OSC52 handled elsewhere) instead of the terminal writer
  3. Discard the stale Clipboard handle and obtain a fresh one from the live terminal context

Example fix

// before
if let Err(err) = clipboard.write_text(text) {
    eprintln!("copy failed: {err}");
}
// after
if let Err(err) = clipboard.write_text(text) {
    if err.to_string().contains("writer stopped") {
        clipboard = Clipboard::new(&terminal_context); // rebuild writer
    }
}
Defensive patterns

Strategy: try-catch

Validate before calling

// Best-effort liveness probe: a disconnected channel fails fast.
fn writer_alive(tx: &std::sync::mpsc::Sender<Request>) -> bool {
    tx.send(Request::Ping).is_ok() // or check an AtomicBool liveness flag
}

Type guard

fn is_disconnected(err: &anyhow::Error) -> bool {
    err.to_string().contains("writer stopped")
}

Try / catch

match clipboard.write_text(text) {
    Ok(()) => {},
    Err(e) if is_disconnected(&e) => rebuild_clipboard_writer_and_retry(),
    Err(e) => log::warn!("clipboard unavailable: {e}"),
}

Prevention

When it happens

Trigger: Calling enqueue_terminal_write (via write_text with ClipboardWriteOrder::TerminalClientOnly) after the writer thread has terminated — typically because the worker saw a shutdown signal, panicked, or the TUI terminal context was torn down while a clipboard write was still attempted.

Common situations: Clipboard write racing app shutdown or terminal teardown; writer thread panic from an invalid escape-sequence target; a plugin or test harness keeping a stale Clipboard handle after the terminal backend was dropped.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22). Data as JSON: /api/errors/a1f27a737d00c8d0. Report an issue: GitHub.

Appendix: source

Thrown at crates/tui/src/tui/clipboard.rs:291

            })
            .context("spawn terminal clipboard writer")?;
        Ok(Self {
            request_tx,
            completion_rx,
        })
    }

    fn enqueue(&self, text: &str, in_tmux: bool) -> Result<()> {
        let request = TerminalClipboardWriteRequest {
            text: text.to_string(),
            in_tmux,
        };
        self.request_tx.try_send(request).map_err(|err| match err {
            std::sync::mpsc::TrySendError::Full(_) => {
                anyhow::anyhow!("another terminal clipboard write is still queued")
            }
            std::sync::mpsc::TrySendError::Disconnected(_) => {
                anyhow::anyhow!("terminal clipboard writer stopped")
            }
        })
    }

    fn poll_completion(&self) -> Option<TerminalClipboardWriteCompletion> {
        self.completion_rx.try_recv().ok()
    }
}

/// Clipboard reader/writer helper.
pub struct ClipboardHandler {
    terminal_context: TerminalClipboardContext,
    terminal_writer: Option<TerminalClipboardWriter>,
    #[cfg(all(target_os = "linux", not(target_env = "ohos"), not(test)))]
    primary: Option<primary::PrimarySelection>,
    #[cfg(test)]
    primary_enabled: bool,
    #[cfg(test)]

View on GitHub (pinned to 73e0f67d83)