jdx/mise · error

brew-cask: APPDIR artifact '{}' is ambiguous: {}

Error message

brew-cask: APPDIR artifact '{}' is ambiguous: {}

What it means

A `$APPDIR/` artifact source matched more than one app bundle. `appdir_artifact_source` takes the first path component as a bundle name, ASCII case-insensitive suffix-matches it against every declared app artifact (both source and target names), keeps candidates where `target/suffix` is an existing file, and bails when several distinct matches remain because the artifact cannot be resolved unambiguously.

Source

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

    for app in apps {
        let target = app_target_path(app.target_name())?;
        let bundle = Path::new(bundle);
        if !path_ends_with_ignore_ascii_case(Path::new(&app.source), bundle)
            && !path_ends_with_ignore_ascii_case(&target, bundle)
        {
            continue;
        }
        let path = target.join(&suffix);
        if path.is_file() {
            matches.push(path);
        }
    }
    matches.sort();
    matches.dedup();
    match matches.as_slice() {
        [] => Ok(None),
        [path] => Ok(Some(path.clone())),
        _ => bail!(
            "brew-cask: APPDIR artifact '{}' is ambiguous: {}",
            source,
            matches
                .iter()
                .map(|path| path.display().to_string())
                .collect::<Vec<_>>()
                .join(", ")
        ),
    }
}

fn find_generated_completion_file(root: &Path, executable: &str) -> Result<Option<PathBuf>> {
    let executable_path = Path::new(executable);
    let direct = root.join(executable_path);
    if direct.is_file() {
        return Ok(Some(direct));
    }
    let matches = find_file_artifacts(root, executable_path);

View on GitHub (pinned to 6f52dcdf99)

Solutions

  1. Disambiguate the source: use the exact target name or a longer path that matches only one app
  2. Rename or split app artifacts so each bundle resolves uniquely
  3. Drop stale duplicate app entries from the cask definition after verifying which app is real

Example fix

# before - two apps end with MyApp.app, artifact matches both
app(name: "MyApp.app", target: "MyApp.app")
app(name: "Extras/MyApp.app", target: "MyApp-Extras.app")
completion(source: "$APPDIR/MyApp.app/Contents/Resources/_myapp", ...)
# after - reference the unique target name
completion(source: "$APPDIR/MyApp-Extras.app/Contents/Resources/_myapp", ...)
Defensive patterns

Strategy: validation

Validate before calling

// Pre-resolve appdir artifact sources and require a unique app match
let matches = appdir_artifact_source(source, &artifacts.apps)?;
match matches {
    None => /* skip or warn: source file absent in all bundles */,
    Some(_) => /* safe to proceed */,
}
// appdir_artifact_source itself bails on ambiguity; enumerate apps first:
let bundle = Path::new(source.strip_prefix("$APPDIR/")?).components().next()?;
let owners = artifacts.apps.iter().filter(|app| path_ends_with_ignore_ascii_case(Path::new(&app.source), &bundle)).count();
if owners > 1 { return Err(eyre!("appdir source '{}' matches {} apps; disambiguate", source, owners)); }

Try / catch

if err.to_string().contains("is ambiguous") {
    // the message lists every matched path; pick the intended one and lengthen the source
}

Prevention

When it happens

Trigger: A cask declaring multiple apps whose source or target names end with the same bundle name (e.g. `MyApp.app` and `Extras/MyApp.app`) while a `$APPDIR/MyApp.app/...` artifact matches both; case-insensitive matching collapsing two spellings of the same name.

Common situations: Casks bundling CLI and GUI apps with overlapping names; renamed app artifacts across versions leaving duplicates in the artifact list; target-name collisions between declared apps.

Related errors


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