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
- Fix the packslip manifest so the command name is a bare executable file name (e.g. `mybin`, not `bin/mybin`).
- Pass a plain shell name (`bash`, `zsh`, `fish`) without slashes or path traversal segments.
- Update mise or the packslip statement if the tool legitimately installs a binary in a subdirectory — command_name should strip to the file name.
- 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
- Always pass canonical shell names (bash/zsh/fish) to completion commands
- Ensure packslip manifests declare bare command names
- Validate user/script input before interpolating into shell or tool arguments
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
- cli-spec entry names
- has no executable called
- mise cannot derive completions from a
- is not an active, installed tool or one of their executables
- resource command produced no output
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)