{"record":{"id":"379cdd6968f66613","repo":"gitbutlerapp/gitbutler","slug":"cli-installation-failed","errorCode":null,"errorMessage":"CLI installation failed ({}): {}","messagePattern":"CLI installation failed \\((.+?)\\): (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/but-action/src/cli.rs","lineNumber":225,"sourceCode":"        do shell script (\"/bin/mkdir -p \" & targetDirectory & \" || exit $?; \" & ¬\n            \"if [ -L \" & targetPath & \" ] && [ \" & symlinkPolicy & \" = replace ]; then \" & ¬\n            \"/bin/rm \" & targetPath & \" || exit $?; \" & ¬\n            \"elif [ -e \" & targetPath & \" ] || [ -L \" & targetPath & \" ]; then \" & ¬\n            \"echo 'CLI destination already exists' >&2; exit 1; fi; \" & ¬\n            \"/bin/ln -s -h \" & sourcePath & \" \" & targetPath) ¬\n            with prompt \"GitButler needs administrator access to install but into /usr/local/bin.\" ¬\n            with administrator privileges\n        return \"gitbutler-cli-installed\"\n    on error messageText number errorNumber\n        if errorNumber is -128 then return \"gitbutler-cli-install-cancelled\"\n        error messageText number errorNumber\n    end try\nend run\n\"#;\n\n#[cfg(any(target_os = \"macos\", all(test, unix)))]\nfn check_cli_install_output(output: std::process::Output) -> anyhow::Result<()> {\n    anyhow::ensure!(\n        output.status.success(),\n        \"CLI installation failed ({}): {}\",\n        output.status,\n        String::from_utf8_lossy(&output.stderr).trim()\n    );\n    if output.stdout == b\"gitbutler-cli-install-cancelled\\n\" {\n        return Err(\n            anyhow!(\"Administrator authorization was cancelled\").context(ErrorContext::new_static(\n                Code::CliInstallCancelled,\n                \"CLI install cancelled\",\n            )),\n        );\n    }\n    anyhow::ensure!(\n        output.stdout == b\"gitbutler-cli-installed\\n\",\n        \"Unexpected CLI installer response\"\n    );\n    Ok(())","sourceCodeStart":207,"sourceCodeEnd":243,"githubUrl":"https://github.com/gitbutlerapp/gitbutler/blob/58e5313667b857ef39a730e380af31816a7b1768/crates/but-action/src/cli.rs#L207-L243","documentation":"check_cli_install_output validates the result of the macOS AppleScript that installs the CLI symlink with administrator privileges. When the elevated shell script exits non-zero, this error reports the exit status plus the script's trimmed stderr. It wraps real failures of mkdir/rm/ln inside the privileged script (e.g. the destination already exists and symlinkPolicy is not replace, or rm/ln failed).","triggerScenarios":"install_cli_link_escalated runs the INSTALL_CLI_SCRIPT AppleScript with administrator privileges and the underlying shell command fails: destination exists and is not a replaceable symlink ('CLI destination already exists'), /bin/rm of an old symlink fails, /bin/ln -s -h fails, or /bin/mkdir -p of the target directory fails.","commonSituations":"A regular file or directory already occupies /usr/local/bin/but so ln fails; the admin script was denied mid-way leaving inconsistent state; a read-only or odd-permission /usr/local/bin; an old GitButler version left an entry the 'keep' symlink policy refuses to touch.","solutions":["Read the stderr in the error message; it names which command inside the script failed.","If the destination exists as a regular file/directory, remove or move it: `sudo mv /usr/local/bin/but /usr/local/bin/but.bak`, then retry.","Retry the install choosing the Replace symlink policy if you want the existing symlink overwritten.","Check permissions on the target directory: `ls -ld /usr/local/bin` and ensure it is writable by root.","If the authorization dialog itself failed, rerun the install and approve the administrator prompt."],"exampleFix":"// before: destination occupied by a regular file\nError: CLI installation failed (exit status: 1): CLI destination already exists\n\n// after\n$ sudo mv /usr/local/bin/but /usr/local/bin/but.bak\n$ retry install -> stdout 'gitbutler-cli-installed'","handlingStrategy":"try-catch","validationCode":"let dest = \"/usr/local/bin/but\";\nif std::path::Path::new(dest).exists() && !std::path::Path::new(dest).is_symlink() {\n    eprintln!(\"{dest} exists and is not a symlink; move it aside before installing\");\n}","typeGuard":null,"tryCatchPattern":"match install_cli_link_escalated(...) {\n    Err(e) => {\n        let msg = format!(\"{e:#}\");\n        if msg.contains(\"CLI installation failed\") {\n            // inspect stderr portion, clear the destination or fix permissions, then retry\n        }\n    }\n    ok => {}\n}","preventionTips":["Ensure the destination path is free (or a replaceable symlink) before starting an elevated install.","Verify /usr/local/bin exists and is root-writable.","Do not wrap or filter the installer script's stdout/stderr."],"tags":["macos","cli-installation","process-exit","shell-script"],"backgroundTag":"git-command-failed","analyzedSha":"58e5313667b857ef39a730e380af31816a7b1768","analyzedAt":"2026-09-18T06:50:32.052Z","contentChangedAt":"2026-09-18T06:50:32.052Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}