jdx/mise · error

brew-cask: installer executable '{}' was not found

Error message

brew-cask: installer executable '{}' was not found

What it means

After confirming the installer executable sits inside the staging directory, mise requires it to exist as a regular file before running it. This error means the joined path is not a file: typically a wrong filename in the cask, a changed artifact layout, or a missing/failed download+extraction step.

Source

Thrown at src/system/packages/brew/cask.rs:2323

    // `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 9dcfcaa0dc)

Solutions

  1. List the staged artifact directory and compare its contents with the executable value in the cask
  2. Update the cask (or the tap) so executable matches the real path inside the artifact
  3. Clear the cached download/staging leftovers and retry the install
  4. If the name is right but nesting differs, adjust the stanza to include the extra directory level

Example fix

# before -- binary is nested inside the .app bundle
executable: "Install Me"

# after
executable: "Install Me.app/Contents/MacOS/Install Me"
Defensive patterns

Strategy: validation

Validate before calling

let exe = stage.join(&installer.executable);
if !exe.is_file() {
    anyhow::bail!(
        "installer '{}' missing from stage; stage contains: {:?}",
        installer.executable,
        std::fs::read_dir(stage)?.flatten().map(|e| e.file_name()).collect::<Vec<_>>()
    );
}

Try / catch

match run_installer_artifact(stage, &installer, &copied) {
    Err(e) if e.to_string().contains("was not found") => {
        // clear the cached download/staging leftovers and retry once
        clean_stage(stage)?;
        run_installer_artifact(stage, &installer, &copied)?
    }
    other => other?,
}

Prevention

When it happens

Trigger: executable value with a typo or wrong case; the archive staged with an extra nesting level so the binary sits deeper; the download step failed or was skipped so the stage is empty; executable names a directory.

Common situations: Upstream releases renaming the installer binary between versions; stale tap casks; partially downloaded/cached artifacts; dmg layouts that differ from the stanza.

Related errors


AI-assisted analysis of jdx/mise@9dcfcaa0dc (2026-08-17). Data as JSON: /api/errors/7d8f032f716f759e. Report an issue: GitHub.