jdx/mise · error

invalid completion cache identity

Error message

invalid completion cache identity

What it means

completion_cache_path builds the on-disk path for a cached shell completion under `<install>/resources/completions-v2/<bin>/<shell>.completion`. Before doing so it validates that both the binary name (from `packslip::command_name`) and the shell name are plain file names (no path separators, `.`, or `..`). mise throws this error to refuse constructing a cache path from components that could escape the intended directory.

Solutions

  1. Fix the packslip manifest so the command name is a bare executable file name (e.g. `mybin`, not `bin/mybin`).
  2. Pass a plain shell name (`bash`, `zsh`, `fish`) without slashes or path traversal segments.
  3. Update mise or the packslip statement if the tool legitimately installs a binary in a subdirectory — command_name should strip to the file name.
  4. If you are calling internal APIs, sanitize inputs with the same `file::is_plain_file_name` check before invoking.

Example fix

// before
mise completions mytool "bin/mytool"
// after
mise completions mytool bash
Defensive patterns

Strategy: validation

Validate before calling

fn is_safe_component(s: &str) -> bool { !s.is_empty() && s != "." && s != ".." && !s.contains('/') && !s.contains('\\') }
if !is_safe_component(shell) || !is_safe_component(bin) { return Err("invalid completion identifiers"); }

Type guard

fn is_plain_file_name(s: &str) -> bool { !s.is_empty() && !s.contains('/') && !s.contains('\\') && s != "." && s != ".." }

Prevention

When it happens

Trigger: Calling `mise completions <tool> <shell>` (via completion_script -> completion_cache_path) when the packslip's command_name resolves to something with path components, or the shell argument contains `/`, `..`, or similar non-plain-file characters.

Common situations: A packslip manifest declaring a command name with a directory component; a user or script passing a malformed shell name like `bash/` or an absolute path; downstream automation interpolating untrusted values into the shell argument.

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@533346cc37 (2026-09-17). Data as JSON: /api/errors/84eee37a0c3303fa. Report an issue: GitHub.

Appendix: source

Thrown at src/packslip.rs:1438

/// The `shell` completion script for `tool`, from the packslip of the
/// version that is active right now.
fn completion_bin<'a>(statement: &'a Statement, tool: Option<&'a str>) -> Option<&'a str> {
    tool.map(packslip::command_name)
        .filter(|name| {
            statement
                .predicate
                .artifacts
                .iter()
                .flat_map(|a| &a.bin)
                .any(|b| b.name == *name)
        })
        .or_else(|| statement.sole_bin())
}

fn completion_cache_path(install_path: &Path, tool: &str, shell: &str) -> Result<PathBuf> {
    let bin = packslip::command_name(tool);
    if !file::is_plain_file_name(bin) || !file::is_plain_file_name(shell) {
        bail!("invalid completion cache identity");
    }
    Ok(install_path
        .join(RESOURCES_DIR)
        .join("completions-v2")
        .join(bin)
        .join(format!("{shell}.completion")))
}

pub(crate) async fn completion_script(
    config: &Arc<Config>,
    tool: &str,
    shell: &str,
) -> Result<String> {
    let ts = config.get_toolset().await?;
    let (backend, tv) = find_tool(config, ts, tool).await?;
    let install_path = tv.install_path();
    let Some(statement) = statement(&install_path)? else {
        bail!(

View on GitHub (pinned to 533346cc37)