xai-org/grok-build · error

pbcopy exited with status {status}

Error message

pbcopy exited with status {status}

What it means

On the macOS pbcopy write leg, if the spawned pbcopy process finishes with a non-zero exit status after the 2-second deadline wait, the leg reports failure with this message. It distinguishes 'pbcopy ran but failed' from spawn failures or timeouts.

Source

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

            ..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
    }

    /// Read an image from the macOS clipboard via `osascript`.
    ///
    /// Probes PNG, TIFF, then JPEG in a single `osascript` invocation
    /// using nested `try` blocks. This avoids spawning up to 3 separate

View on GitHub (pinned to bc7f02eddd)

Solutions

  1. Check whether the environment has access to the macOS user pasteboard (run `echo hi | pbcopy && pbpaste` manually)
  2. Run inside a regular graphical/login session rather than an SSH or restricted context
  3. Rely on the arboard leg, which set_text attempts alongside pbcopy, or fix the session so it works
  4. Inspect the reported status code for the specific pbcopy failure
Defensive patterns

Strategy: try-catch

Validate before calling

// Confirm pbcopy works in the current session
let ok = std::process::Command::new("sh")
    .arg("-c").arg("echo test | pbcopy && [ \"$(pbpaste)\" = test ]")
    .status().map(|s| s.success()).unwrap_or(false);

Try / catch

match clipboard::set_text(&text) {
    Err(e) if e.to_string().contains("pbcopy exited with status") => {
        eprintln!("pbcopy failed ({e}); trying alternate backend");
        // fall back to arboard-based path or manual instructions
    }
    other => other?,
}

Prevention

When it happens

Trigger: Calling set_text on macOS when pbcopy starts but exits non-zero — typically because the pasteboard is unavailable in the session (SSH without a proper launchd user session, sandbox restrictions).

Common situations: SSH sessions on macOS where the launchd context lacks a clipboard; automation tools running pbcopy under restricted contexts; full pasteboard daemon issues.

Related errors


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