{"record":{"id":"1de2dd4889ae560e","repo":"jdx/mise","slug":"completion-target-is-not-an-owned-caskroom-symlink","errorCode":null,"errorMessage":"completion target is not an owned Caskroom symlink: {}","messagePattern":"completion target is not an owned Caskroom symlink: (.+?)","errorType":"exception","errorClass":"eyre::Report","httpStatus":null,"severity":"error","filePath":"src/system/packages/brew/cask.rs","lineNumber":7106,"sourceCode":"    }\n    let completion_roots = [\n        CompletionShell::Bash,\n        CompletionShell::Fish,\n        CompletionShell::Zsh,\n        CompletionShell::Pwsh,\n    ]\n    .map(default_completion_dir);\n    for path in &receipt.completions {\n        let record = records\n            .get(path)\n            .ok_or_else(|| eyre!(\"missing completion target record\"))?;\n        if record.fingerprint.kind != CaskTargetKind::Symlink\n            || !completion_roots\n                .iter()\n                .any(|root| path_is_below(path, root))\n            || !symlink_resolves_below(path, &candidate.version_dir)\n        {\n            bail!(\n                \"completion target is not an owned Caskroom symlink: {}\",\n                path.display()\n            );\n        }\n    }\n    for record in &receipt.targets {\n        if !cask_target_record_matches(record)? {\n            bail!(\"artifact target has changed: {}\", record.path.display());\n        }\n    }\n    Ok(())\n}\n\nfn path_is_below(path: &Path, root: &Path) -> bool {\n    path.strip_prefix(root)\n        .is_ok_and(|relative| relative.components().next().is_some())\n}\n","sourceCodeStart":7088,"sourceCodeEnd":7124,"githubUrl":"https://github.com/jdx/mise/blob/9dcfcaa0dc8747a2577d3270b69bb9d8313b2807/src/system/packages/brew/cask.rs#L7088-L7124","documentation":"Completion targets must be symlinks under a default completion directory for one of the supported shells (bash, fish, zsh, pwsh) and resolve into the cask's Caskroom version directory. The prune refuses to touch completion files that are real files, sit in custom completion dirs, or point elsewhere.","triggerScenarios":"validate_cask_prune_candidate, completions loop: fingerprint kind != Symlink, path not below any default_completion_dir(shell) root, or symlink_resolves_below(path, version_dir) false. Produced when shell completion files were copied over the links, a framework (e.g. a shell plugin manager) regenerated them, or completions were installed into a non-default directory.","commonSituations":"oh-my-zsh / Fisher / completions managers rewriting completion files; user copying the completion into a custom fpath dir; stale links after a Homebrew relink.","solutions":["Recreate the completion as a symlink into Caskroom/<token>/<version>/ under the shell's default completion directory","Reinstall the cask to regenerate completions and their receipt, then prune","Remove manually-installed completion files yourself and uninstall the cask instead of pruning"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Check completions are symlinks under a default completion dir pointing\n// into the cask version dir.\nfn completion_ok(path: &Path, version_dir: &Path) -> bool {\n    let roots = [CompletionShell::Bash, CompletionShell::Fish, CompletionShell::Zsh, CompletionShell::Pwsh]\n        .map(default_completion_dir);\n    path.symlink_metadata().map(|m| m.file_type().is_symlink()).unwrap_or(false)\n        && roots.iter().any(|root| path_is_below(path, root))\n        && symlink_resolves_below(path, version_dir)\n}","typeGuard":"fn is_default_dir_completion(path: &Path) -> bool {\n    [CompletionShell::Bash, CompletionShell::Fish, CompletionShell::Zsh, CompletionShell::Pwsh]\n        .map(default_completion_dir)\n        .iter()\n        .any(|root| path_is_below(path, root))\n}","tryCatchPattern":"// Skip the affected cask, keep pruning the rest; report which completion path failed.\nif let Err(reason) = validate_cask_prune_candidate(candidate) {\n    warn!(\"brew-cask:{}: {reason:#}\", candidate.token);\n    continue;\n}","preventionTips":["Let the cask own its completion symlinks; don't let plugin managers overwrite them with copies","If a framework replaces completions, reinstall the cask before pruning"],"tags":["brew","cask","prune","completions","symlink","integrity"],"backgroundTag":"symlink-integrity-check-failed","analyzedSha":"9dcfcaa0dc8747a2577d3270b69bb9d8313b2807","analyzedAt":"2026-08-17T14:28:50.624Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}