{"record":{"id":"84eee37a0c3303fa","repo":"jdx/mise","slug":"invalid-completion-cache-identity","errorCode":null,"errorMessage":"invalid completion cache identity","messagePattern":"invalid completion cache identity","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/packslip.rs","lineNumber":1438,"sourceCode":"/// The `shell` completion script for `tool`, from the packslip of the\n/// version that is active right now.\nfn completion_bin<'a>(statement: &'a Statement, tool: Option<&'a str>) -> Option<&'a str> {\n    tool.map(packslip::command_name)\n        .filter(|name| {\n            statement\n                .predicate\n                .artifacts\n                .iter()\n                .flat_map(|a| &a.bin)\n                .any(|b| b.name == *name)\n        })\n        .or_else(|| statement.sole_bin())\n}\n\nfn completion_cache_path(install_path: &Path, tool: &str, shell: &str) -> Result<PathBuf> {\n    let bin = packslip::command_name(tool);\n    if !file::is_plain_file_name(bin) || !file::is_plain_file_name(shell) {\n        bail!(\"invalid completion cache identity\");\n    }\n    Ok(install_path\n        .join(RESOURCES_DIR)\n        .join(\"completions-v2\")\n        .join(bin)\n        .join(format!(\"{shell}.completion\")))\n}\n\npub(crate) async fn completion_script(\n    config: &Arc<Config>,\n    tool: &str,\n    shell: &str,\n) -> Result<String> {\n    let ts = config.get_toolset().await?;\n    let (backend, tv) = find_tool(config, ts, tool).await?;\n    let install_path = tv.install_path();\n    let Some(statement) = statement(&install_path)? else {\n        bail!(","sourceCodeStart":1420,"sourceCodeEnd":1456,"githubUrl":"https://github.com/jdx/mise/blob/533346cc374382b41ec5ff70536252b2e96e725c/src/packslip.rs#L1420-L1456","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nmise completions mytool \"bin/mytool\"\n// after\nmise completions mytool bash","handlingStrategy":"validation","validationCode":"fn is_safe_component(s: &str) -> bool { !s.is_empty() && s != \".\" && s != \"..\" && !s.contains('/') && !s.contains('\\\\') }\nif !is_safe_component(shell) || !is_safe_component(bin) { return Err(\"invalid completion identifiers\"); }","typeGuard":"fn is_plain_file_name(s: &str) -> bool { !s.is_empty() && !s.contains('/') && !s.contains('\\\\') && s != \".\" && s != \"..\" }","tryCatchPattern":null,"preventionTips":["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"],"tags":["path-validation","completion","packslip"],"backgroundTag":"path-traversal-blocked","analyzedSha":"533346cc374382b41ec5ff70536252b2e96e725c","analyzedAt":"2026-09-17T13:35:38.149Z","contentChangedAt":"2026-09-17T13:35:38.149Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}