jdx/mise · error

brew-cask: binary artifact '{}' was not staged

Error message

brew-cask: binary artifact '{}' was not staged

What it means

link_binary requires the staged copy of a cask binary artifact to exist at caskroom_binary_path before it can symlink the binary into the target bin directory. If that path is neither a regular file nor a symlink, staging never produced it and mise refuses to create a link to nothing. It is the missing-file counterpart of the dangling-symlink error above.

Source

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

    }
    target_app_dir()
}

fn link_binary(caskroom: &Path, appdir: &Path, binary: &BinaryArtifact) -> Result<()> {
    let caskroom_binary = caskroom_binary_path(caskroom, appdir, binary)?;
    if !caskroom_binary.is_file() {
        if caskroom_binary
            .symlink_metadata()
            .is_ok_and(|metadata| metadata.file_type().is_symlink())
        {
            let target = std::fs::read_link(&caskroom_binary)?;
            bail!(
                "brew-cask: binary artifact '{}' was staged but symlink target '{}' does not exist",
                binary.source,
                target.display()
            );
        }
        bail!(
            "brew-cask: binary artifact '{}' was not staged",
            binary.source
        );
    }
    let target = binary.target_path(appdir)?;
    if let Some(parent) = target.parent() {
        create_dir_all_elevating(parent)?;
    }
    make_symlink_elevating(&caskroom_binary, &target)?;
    Ok(())
}

fn link_command_wrapper(caskroom: &Path, wrapper: &CommandWrapperArtifact) -> Result<()> {
    let source = wrapper.caskroom_path(caskroom);
    if !source.is_file() {
        bail!(
            "brew-cask: command wrapper '{}' was not staged",
            wrapper.name

View on GitHub (pinned to 6f52dcdf99)

Solutions

  1. Verify what actually shipped: list the staged payload (e.g. `find <caskroom> -type f -perm +111`) and locate where the CLI now lives.
  2. Update the binary stanza source to the new path in the current version's payload.
  3. If the app genuinely no longer ships a CLI, remove the binary stanza from the cask metadata.
  4. Reinstall the cask to rule out a truncated download/staging failure.

Example fix

# before — old layout
"binary": ["MyApp.app/Contents/MacOS/myapp"]

# after — new layout after upstream moved the CLI
"binary": ["MyApp.app/Contents/Resources/app/bin/myapp"]
Defensive patterns

Strategy: validation

Validate before calling

# verify each stanza source exists in the payload before install
for src in "$(jq -r '.binaries[].source' meta.json)"; do
  find "<extracted-payload>" -path "*$src" -print -quit | grep -q . || echo "missing source: $src"
done

Prevention

When it happens

Trigger: The cask's binary stanza source glob/path matched nothing in the extracted payload: upstream changed the app's internal layout (moved the CLI, renamed Contents/MacOS), the stanza was written for a different version, or the staging step filtered/skipped the file. Checked via `!caskroom_binary.is_file()` at src/system/packages/brew/cask.rs:4883.

Common situations: A new app version restructures its .app bundle so the old binary path no longer exists; cask metadata lagging behind a release; stanza globs that silently matched zero files; payload extraction that skipped an oddly-named executable.

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


AI-assisted analysis of jdx/mise@6f52dcdf99 (2026-08-22). Data as JSON: /api/errors/f00c77c4fd00f98b. Report an issue: GitHub.