xai-org/grok-build · error

arboard unavailable

Error message

arboard unavailable

What it means

arboard_lease (crates/codegen/xai-grok-shared/src/clipboard.rs:1313) creates an arboard Clipboard on a worker thread; when Clipboard::new() fails or does not complete, the lease is None and this error is returned. It means no in-process clipboard backend could be initialized — usually no accessible display/selection server.

Source

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

                }
                match spawn_with_deadline(
                    "clipboard-init",
                    DISPLAY_CONN_WAIT,
                    arboard::Clipboard::new,
                ) {
                    Ok(Ok(clipboard)) => Some(parking_lot::Mutex::new(clipboard)),
                    Ok(Err(e)) => {
                        tracing::debug!("arboard Clipboard::new failed: {e}");
                        None
                    }
                    Err(e) => {
                        tracing::debug!("arboard Clipboard::new did not complete: {e}");
                        None
                    }
                }
            })
            .as_ref()
            .ok_or_else(|| anyhow::anyhow!("arboard unavailable"))
    }

    /// Deadline for in-process arboard reads. The Wayland data-control read has
    /// no internal timeout and blocks forever on a hung selection owner (the
    /// X11 path has a 4 s budget), so reads run on a worker thread that is
    /// 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()

View on GitHub (pinned to bc7f02eddd)

Solutions

  1. Set DISPLAY (X11) or WAYLAND_DISPLAY correctly for the running process.
  2. Run inside a graphical session or use x/wayland forwarding for SSH.
  3. Install the missing Wayland/X11 clipboard protocol support or fall back to CLI tools (xclip/wl-copy/pbcopy).
  4. If init is timing out, check for a hung compositor/selection owner.

Example fix

// before
clipboard.arboard_set_text("hi")?; // fails headless
// after
if std::env::var_os("WAYLAND_DISPLAY").or_else(|| std::env::var_os("DISPLAY")).is_some() {
    clipboard.arboard_set_text("hi")?;
} else {
    eprintln!("no display; clipboard skipped");
}
Defensive patterns

Strategy: fallback

Validate before calling

fn has_display() -> bool {
    std::env::var_os("WAYLAND_DISPLAY").is_some()
        || std::env::var_os("DISPLAY").is_some()
}

Try / catch

match arboard_set_text(text) {
    Err(e) if e.to_string() == "arboard unavailable" => cli_set_text_fallback(text),
    other => other,
}

Prevention

When it happens

Trigger: arboard_set_text on a headless machine (no X11/Wayland display), with DISPLAY/WAYLAND_DISPLAY unset or pointing at a dead server, or when the clipboard init timed out and returned None.

Common situations: SSH sessions without X forwarding, CI containers, Wayland compositors without the data-control protocol, Windows services in session 0.

Related errors


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