jdx/mise · error

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

Error message

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

What it means

mise validates that a cask's declared completion target path, after shell-specific directory resolution, stays inside the managed completions tree. If any path component is `..`, the target could escape that tree, so mise rejects it before any filesystem writes — a path traversal guard on completion stanzas.

Source

Thrown at src/system/packages/brew/cask/mod.rs:2955

}

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 afd2eddd3a)

Solutions

  1. Rewrite the completion target in the cask definition as a clean relative path without `..`
  2. Use the shell's default completion directory implicitly instead of overriding with a parent-relative path
  3. Treat this error as a security signal if the cask came from an untrusted source — do not bypass it

Example fix

// before (cask stanza)
completion "../../usr/local/share/zsh/site-functions/_x"
// after
completion "_x"  # placed under the managed completion dir
Defensive patterns

Strategy: validation

Validate before calling

let t = std::path::Path::new(target);
assert!(!t.components().any(|c| matches!(c, std::path::Component::ParentDir)), "completion target must not contain '..'");

Type guard

fn has_no_parent_components(p: &std::path::Path) -> bool {
  !p.components().any(|c| matches!(c, std::path::Component::ParentDir))
}

Try / catch

if let Err(e) = result {
  if e.contains("must not contain '..'") {
    eprintln!("completion target rejected as traversal; rewrite it as a relative path under the completion dir");
  }
}

Prevention

When it happens

Trigger: `target.components().any(|c| matches!(c, Component::ParentDir))` is true while computing the final completion destination (e.g. from a cask stanza like `"../../etc/foo"`).

Common situations: A hand-written or third-party cask declares a completion path containing `..`; templating in a cask expands to a path with parent references; a typo like `".."` in a relative completion path.

Understand the failure class

Background: Path traversal blocked: "path escapes the workspace" and "outside site root" errors when a path will not stay inside its allowed directory — this error's family across 26 libraries.

Related errors


AI-assisted analysis of jdx/mise@afd2eddd3a (2026-09-09). Data as JSON: /api/errors/451ade49026e26ef. Report an issue: GitHub.