jdx/mise · error
brew-cask: installer executable
Error message
brew-cask: installer executable '{}' was not found What it means
mise's brew-cask backend refuses to run a cask installer when the resolved installer executable does not exist on disk as a regular file. The backend resolves the executable path from the cask's staged installer stanza and validates it before invoking it, so a missing or non-file path (directory, broken symlink, absent artifact) aborts installation instead of spawning a failing command. This protects against casks whose staged layout does not match what the cask formula declares.
Solutions
- Re-run the cask install with a clean staging area so the artifact is re-downloaded and fully extracted (e.g. remove the cached download and reinstall the cask).
- Verify the executable path in the cask formula actually exists in the staged bundle and is a regular file.
- Check for a broken symlink at the expected path and repair the source of that link.
- Update the cask/mise backend definitions, then retry; if the cask upstream changed its installer name, the formula must be updated.
- Ensure the filesystem hosting the staging directory is mounted and writable (not an unmounted or read-only volume).
Example fix
// before (formula references old name)
installer { script: { executable: "OldInstaller.app/Contents/MacOS/OldInstaller" } }
// after
installer { script: { executable: "NewInstaller.app/Contents/MacOS/NewInstaller" } } Defensive patterns
Strategy: validation
Validate before calling
let exe = std::path::Path::new(&installer.executable);
if !exe.is_file() {
eprintln!("installer executable missing: {}", exe.display());
std::process::exit(1);
} Type guard
fn is_regular_file(p: &std::path::Path) -> bool {
p.is_file()
} Prevention
- Always install casks through mise so staging completes before the installer runs.
- Clear the brew cask cache if a prior install was interrupted, then reinstall.
- Keep cask definitions updated when upstream renames installer binaries.
- Avoid pruning or hand-editing staging/caskroom directories.
When it happens
Trigger: Installing a cask whose installer stanza points to an executable that was never staged (bad cask formula), the staged artifact was pruned or partially extracted, the executable path resolves to a directory or dangling symlink, or the install ran with a changed staging directory/version mismatch so the expected binary is absent.
Common situations: Homebrew cask updates where the upstream project renamed its installer binary; interrupted or partial downloads; running mise against a cask whose staged files were manually cleaned from ~/Library/Caches or the brew cache; macOS version changes altering bundle layout.
Understand the failure class
Background: "File not found" and ENOENT errors: why libraries can't find a file that should exist — this error's family across 50 libraries.
Related errors
- brew-cask: installer executable
- brew-cask: binary artifact
- brew-cask: command wrapper
- brew-cask: font artifact
- brew-cask: font artifact
AI-assisted analysis of jdx/mise@533346cc37 (2026-09-17).
Data as JSON: /api/errors/5fdab7f8f66db9c8.
Report an issue: GitHub.
Appendix: source
Thrown at src/system/packages/brew/cask/mod.rs:2388
// `allow_current_user` is true because a per-user appdir such as
// `~/Applications` is legitimately owned by the invoking user.
open_trusted_directory(Path::new("/"), relative, true, true)
}
fn run_installer_artifact(
stage: &Path,
installer: &InstallerArtifact,
copied_files: &BTreeSet<PathBuf>,
) -> Result<()> {
let executable = stage.join(&installer.executable);
if staged_relative_path(stage, &executable).is_none() {
bail!(
"brew-cask: refusing installer executable outside trusted installer roots: {}",
executable.display()
);
}
if !executable.is_file() {
bail!(
"brew-cask: installer executable '{}' was not found",
installer.executable
);
}
let executable = file::desymlink_path(&executable);
if !executable.starts_with(file::desymlink_path(stage)) && !copied_files.contains(&executable) {
bail!(
"brew-cask: refusing installer executable outside trusted installer roots: {}",
executable.display()
);
}
file::make_executable(&executable)?;
let prefix = prefix::prefix();
let mut paths = vec![prefix.join("bin"), prefix.join("sbin")];
if let Some(path) = std::env::var_os("PATH") {
paths.extend(std::env::split_paths(&path));
}
let path = std::env::join_paths(paths)?;View on GitHub (pinned to 533346cc37)