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 separateView on GitHub (pinned to bc7f02eddd)
Solutions
- Check whether the environment has access to the macOS user pasteboard (run `echo hi | pbcopy && pbpaste` manually)
- Run inside a regular graphical/login session rather than an SSH or restricted context
- Rely on the arboard leg, which set_text attempts alongside pbcopy, or fix the session so it works
- 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
- Run inside a regular macOS login/graphical session, not a bare SSH context
- Smoke-test `echo hi | pbcopy` in the target environment before deploying
- Keep the arboard leg enabled so set_text has a second chance
- Check pasteboard daemon health if failures persist
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
- {label} exited with {}: {}
- osascript failed: {stderr}
- {bin} exited with status {status}
- failed to run {label}: {error}
- failed to spawn pbcopy: {e}
AI-assisted analysis of xai-org/grok-build@bc7f02eddd (2026-08-31).
Data as JSON: /api/errors/8060971c205cd446.
Report an issue: GitHub.