jdx/mise · error

brew-cask: completion target '{}' must not contain '..'

Error message

brew-cask: completion target '{}' must not contain '..'

What it means

Before installing a completion artifact, mise resolves the cask's completion target into a concrete path (absolute path used as-is; a name containing '/' joined onto the brew prefix; a bare name placed into the shell's default completion directory) and then rejects any result whose path components include a ParentDir ('..') component. This is a path-traversal guard: a cask must not be able to write completion files outside the intended tree via dot-dot segments.

Source

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

}

fn completion_target_path(shell: CompletionShell, target_name: &str) -> Result<PathBuf> {
    let prefix = prefix::prefix();
    let prefix_str = prefix.to_string_lossy();
    let target_name = target_name.replace("$HOMEBREW_PREFIX", prefix_str.as_ref());
    let path = PathBuf::from(&target_name);
    let target = if path.is_absolute() {
        path
    } else if target_name.contains('/') {
        prefix.join(path)
    } else {
        default_completion_dir(shell).join(completion_filename(shell, &target_name)?)
    };
    if target
        .components()
        .any(|component| matches!(component, Component::ParentDir))
    {
        bail!(
            "brew-cask: completion target '{}' must not contain '..'",
            target.display()
        );
    }
    if !target.starts_with(&prefix) {
        bail!(
            "brew-cask: completion target '{}' must be under {}",
            target.display(),
            prefix.display()
        );
    }
    Ok(target)
}

fn generated_completion_target_path(shell: CompletionShell, base_name: &str) -> Result<PathBuf> {
    match shell {
        CompletionShell::Pwsh => {
            let name = format!("_{}.ps1", base_name);

View on GitHub (pinned to 6f52dcdf99)

Solutions

  1. Rewrite the completion target to a plain, normalized path with no '..' component — e.g. 'zsh/_tool' or an absolute path genuinely under the brew prefix.
  2. For bare filenames, drop any directory part entirely and let mise place the file in the shell's default completion directory.
  3. If you need a specific subdirectory, express it as a forward relative path under the prefix ('share/fish/completions/tool.fish') without traversal.
  4. If the cask is third-party metadata you cannot edit, report it upstream or skip installing that cask with mise.

Example fix

# before
"completions": { "target": "../../../etc/zshrc" }

# after
"completions": { "target": "zsh/_mytool" }
Defensive patterns

Strategy: validation

Validate before calling

# reject traversal before handing metadata to mise
python3 - <<'EOF'
import json,sys
for t in json.load(open(sys.argv[1])).get("completions",[]):
    assert ".." not in t["target"].split("/"), t["target"]
EOF

Prevention

When it happens

Trigger: A cask completion stanza whose target resolves to something like '../../etc/zshrc' or 'foo/../../bar' — either an absolute target containing '..' (checked as-is) or a relative target with '/' whose join with the prefix contains a ParentDir component. The check at src/system/packages/brew/cask.rs:4426 runs on the resolved target before the additional starts_with(prefix) containment check.

Common situations: Hand-written or machine-generated cask metadata with sloppily built relative paths; a cask edited to 'escape' the completion directory; upstream casks that legitimately used '..' in Homebrew itself (Homebrew allows some of this) but are rejected by mise's stricter containment rules.

Related errors


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