xai-org/grok-build · error

failed to spawn pbcopy: {e}

Error message

failed to spawn pbcopy: {e}

What it means

set_text_with_outcome (crates/codegen/xai-grok-shared/src/clipboard.rs:1014) writes text via the macOS `pbcopy` tool; this error wraps the std::io::Error when pbcopy cannot be spawned. It does not indicate pbcopy failed later — a non-zero exit is reported as 'pbcopy exited with status'.

Source

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

    pub fn set_text_with_outcome(text: &str) -> super::NativeWriteOutcome {
        let mut outcome = super::NativeWriteOutcome {
            cli_tools_tried: vec!["pbcopy"],
            ..Default::default()
        };
        let result = (|| -> anyhow::Result<()> {
            // Spooled stdin (not a pipe): a stalled pbcopy must not block the
            // UI thread on the write, and the deadline wait needs stdin closed.
            let stdin = super::spool_for_stdin(text.as_bytes())?;
            let mut cmd = Command::new("pbcopy");
            cmd.stdin(Stdio::from(stdin))
                .stdout(Stdio::null())
                .stderr(Stdio::null());
            xai_grok_tools::util::detach_std_command(&mut cmd);
            #[allow(clippy::disallowed_methods)] // short-lived clipboard helper, waited on below
            let mut child = cmd
                .spawn()
                .map_err(|e| anyhow::anyhow!("failed to spawn pbcopy: {e}"))?;
            let deadline = std::time::Duration::from_secs(2);
            let status = super::wait_with_deadline(&mut child, deadline)?;
            if !status.success() {
                anyhow::bail!("pbcopy exited with status {status}");
            }
            Ok(())
        })();
        match result {
            Ok(()) => {
                outcome.cli_ok = true;
                outcome.cli_ok_tools.push("pbcopy");
                outcome.any_ok = true;
            }
            Err(e) => tracing::debug!("pbcopy failed: {e}"),
        }
        outcome
    }

View on GitHub (pinned to bc7f02eddd)

Solutions

  1. Run on macOS or install/reveal pbcopy; verify with `which pbcopy`.
  2. Fix the process PATH so /usr/bin is present.
  3. Prefer the arboard backend when the platform tool is unavailable.

Example fix

// before
set_text_with_outcome(text)?;
// after
if which("pbcopy").is_none() {
    arboard_set_text(&text)?;
} else {
    set_text_with_outcome(text)?;
}
Defensive patterns

Strategy: fallback

Validate before calling

let pbcopy_ok = std::process::Command::new("pbcopy").arg("-v").output().is_ok();

Try / catch

match set_text_with_outcome(text) {
    Err(e) if e.to_string().contains("failed to spawn pbcopy") => arboard_set_text(text),
    other => other,
}

Prevention

When it happens

Trigger: Calling set_text_with_outcome on a system where pbcopy is missing from PATH or not executable (Linux, minimal container, broken PATH).

Common situations: Cross-platform apps invoking the macOS path by mistake; headless CI runners; PATH sanitization in daemons dropping /usr/bin.

Related errors


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