xai-org/grok-build · error

arboard read timed out

Error message

arboard read timed out

What it means

arboard_read_with_deadline (crates/codegen/xai-grok-shared/src/clipboard.rs:1337) runs arboard reads on a worker thread with a timeout because the Wayland data-control read can block forever on a hung selection owner. If the channel recv times out, it abandons the worker and returns this error. The read produced no result within the deadline.

Solutions

  1. Identify and restart the hung selection owner (clipboard manager / compositor).
  2. Retry the read after the owner recovers; the abandoned worker exits on its own.
  3. Fall back to CLI readers (wl-paste/xclip/pbpaste) when arboard times out repeatedly.
  4. On X11 prefer the built-in 4s budget path; on Wayland ensure the data-control protocol is healthy.

Example fix

// before
let text = arboard_get_text()?;
// after
let text = match arboard_get_text() {
    Ok(t) => t,
    Err(e) if e.to_string().contains("timed out") => cli_read_fallback()?,
    Err(e) => return Err(e),
};
Defensive patterns

Strategy: try-catch

Try / catch

match arboard_get_text() {
    Err(e) if e.to_string() == "arboard read timed out" => {
        // selection owner hung; retry once or use CLI fallback
        cli_read_fallback()
    }
    other => other,
}

Prevention

When it happens

Trigger: arboard_get_text, arboard_get_primary_text, arboard_get_image, or get_file_urls while the Wayland/X11 selection owner is hung or extremely slow to answer the paste request.

Common situations: A crashed-but-alive clipboard manager holding the selection on Wayland; remote apps owning the X11 selection over a slow forwarding link.

Understand the failure class

Related errors


AI-assisted analysis of xai-org/grok-build@bc7f02eddd (2026-08-31). Data as JSON: /api/errors/af01fc7ec6d8d34f. Report an issue: GitHub.

Appendix: source

Thrown at crates/codegen/xai-grok-shared/src/clipboard.rs:1337

    /// abandoned on expiry. The worker's `Clipboard` instance leaks with it;
    /// harmless while the lease keeps the shared backend alive.
    const ARBOARD_READ_WAIT: std::time::Duration = std::time::Duration::from_secs(2);

    fn arboard_read_with_deadline<T: Send + 'static>(
        op: impl FnOnce(&mut arboard::Clipboard) -> anyhow::Result<T> + Send + 'static,
    ) -> anyhow::Result<T> {
        use std::sync::mpsc::RecvTimeoutError;
        if arboard_wayland_bypassed() {
            anyhow::bail!("arboard leg disabled (GROK_CLIPBOARD_NO_DATA_CONTROL)");
        }
        let result = spawn_with_deadline("clipboard-read", ARBOARD_READ_WAIT, move || {
            arboard::Clipboard::new()
                .map_err(anyhow::Error::from)
                .and_then(|mut clipboard| op(&mut clipboard))
        });
        match result {
            Ok(inner) => inner,
            Err(RecvTimeoutError::Timeout) => Err(anyhow::anyhow!("arboard read timed out")),
            Err(RecvTimeoutError::Disconnected) => Err(anyhow::anyhow!("arboard read worker died")),
        }
    }

    fn arboard_get_text() -> anyhow::Result<Option<String>> {
        arboard_read_with_deadline(|clipboard| match clipboard.get_text() {
            Ok(text) if text.is_empty() => Ok(None),
            Ok(text) => Ok(Some(text)),
            Err(arboard::Error::ContentNotAvailable) => Ok(None),
            Err(err) => Err(err.into()),
        })
    }

    #[cfg(target_os = "linux")]
    fn arboard_get_primary_text() -> anyhow::Result<Option<String>> {
        use arboard::{GetExtLinux, LinuxClipboardKind};
        arboard_read_with_deadline(|clipboard| {
            match clipboard

View on GitHub (pinned to bc7f02eddd)