gitbutlerapp/gitbutler · error
Would probably need to run "ln -sf '{}' '{UNIX_LINK_PATH}'"{
Error message
Would probably need to run "ln -sf '{}' '{UNIX_LINK_PATH}'"{privilege} What it means
do_install_cli returns this error when it could not create the /usr/local/bin/but symlink itself and cannot (Linux, or InstallMode::CurrentUserOnly on macOS) or is not allowed to elevate via osascript. It is advisory: the message prints the exact `ln -sf` command the user would need to run manually, optionally suffixed with 'with root permissions'.
Source
Thrown at crates/but-action/src/cli.rs:100
// dedicated Code so the frontend can react based on the code
// rather than matching on an English message.
Err(
anyhow!("osascript exited with status 1").context(ErrorContext::new_static(
Code::CliInstallCancelled,
"CLI install cancelled",
)),
)
} else {
Err(anyhow!(
"osascript exited with status {}",
status
.code()
.map(|c| c.to_string())
.unwrap_or_else(|| "unknown".into())
))
}
} else {
Err(anyhow!(
"Would probably need to run \"ln -sf '{}' '{UNIX_LINK_PATH}'\"{privilege}",
cli_path.display(),
privilege = if can_elevate_privileges {
" with root permissions"
} else {
""
}
))
}
}
fn ensure_cli_path_exists_prior_to_link(cli_path: &std::path::Path) -> anyhow::Result<()> {
if cli_path.exists() {
return Ok(());
}
bail!("Run `CARGO_TARGET_DIR=$PWD/target/tauri cargo build -p but` to build the `but` binary")
}
View on GitHub (pinned to 2497b8007a)
Solutions
- Run the exact command from the error text (it contains the real paths): sudo ln -sf '<cli_path>' /usr/local/bin/but.
- Prefer a user-writable directory already in PATH: mkdir -p ~/.local/bin && ln -sf '<cli_path>' ~/.local/bin/but.
- Verify the '<cli_path>' binary exists first — the installer separately bails with a cargo build hint if it does not.
- If /usr/local/bin/but exists as a regular file (not a symlink), remove it: the installer refuses to overwrite non-symlinks.
Example fix
sudo ln -sf "$PWD/target/tauri/debug/but" /usr/local/bin/but # or user-local: mkdir -p ~/.local/bin && ln -sf "$PWD/target/tauri/debug/but" ~/.local/bin/but && hash -r but --version
Defensive patterns
Strategy: fallback
Validate before calling
use std::path::Path;
fn pick_writable_link_dir() -> std::path::PathBuf {
let usr_local = Path::new("/usr/local/bin");
let probe = usr_local.join(".but-probe");
if usr_local.is_dir() && std::fs::write(&probe, b"").is_ok() {
let _ = std::fs::remove_file(&probe);
return usr_local.to_path_buf();
}
std::env::var_os("HOME").map(|h| Path::new(&h).join(".local/bin")).unwrap()
} Try / catch
match do_install_cli(InstallMode::CurrentUserOnly) {
Ok(()) => Ok(()),
Err(err) => {
// The error text IS the manual instruction: show it as copy-pasteable steps.
show_manual_install_hint(&err.to_string());
Ok(())
}
} Prevention
- Pre-create a user-writable bin directory on PATH before install.
- Never install onto a pre-existing regular file at /usr/local/bin/but.
- Surface the printed ln -sf command in the UI whenever this error fires.
When it happens
Trigger: do_install_cli on Linux, or on macOS with InstallMode::CurrentUserOnly, after std::os::unix::fs::symlink to /usr/local/bin/but failed (directory not user-writable, or the earlier remove+symlink retry failed) — the final else branch emits the manual `ln -sf` hint.
Common situations: Linux systems where /usr/local/bin is root-owned; CI containers running the app as non-root; macOS users choosing current-user-only installation; /usr/local/bin missing entirely.
Related errors
- osascript exited with status {}
- CliInstallCancelled
- Failed to execute command {cmd:?}
- Failed to parse URL
AI-assisted analysis of gitbutlerapp/gitbutler@2497b8007a (2026-08-17).
Data as JSON: /api/errors/b435aea1eb110ffb.
Report an issue: GitHub.