{"record":{"id":"89409f3a9cd01ad4","repo":"jdx/mise","slug":"binary-target-is-not-an-owned-caskroom-symlink-89409f","errorCode":null,"errorMessage":"binary target is not an owned Caskroom symlink: {}","messagePattern":"binary target is not an owned Caskroom symlink: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/system/packages/brew/cask/state.rs","lineNumber":1092,"sourceCode":"            })\n        {\n            bail!(\n                \"app target is outside an allowed Applications directory: {}\",\n                path.display()\n            );\n        }\n    }\n    for path in &receipt.binaries {\n        let record = records\n            .get(path)\n            .ok_or_else(|| eyre!(\"missing binary target record\"))?;\n        if record.fingerprint.kind != CaskTargetKind::Symlink\n            || !allowed_binary_target_roots()\n                .iter()\n                .any(|root| path_is_below(path, root))\n            || !symlink_resolves_below(path, &candidate.version_dir)\n        {\n            bail!(\n                \"binary target is not an owned Caskroom symlink: {}\",\n                path.display()\n            );\n        }\n    }\n    for path in &receipt.fonts {\n        let record = records\n            .get(path)\n            .ok_or_else(|| eyre!(\"missing font target record\"))?;\n        let fonts = font_dir();\n        if record.fingerprint.kind != CaskTargetKind::File\n            || !path_is_below(path, &fonts)\n            || !path.strip_prefix(&fonts).is_ok_and(|relative| {\n                staged_target_matches(record, &candidate.version_dir.join(relative))\n            })\n        {\n            bail!(\n                \"font target is outside the platform font directory: {}\",","sourceCodeStart":1074,"sourceCodeEnd":1110,"githubUrl":"https://github.com/jdx/mise/blob/533346cc374382b41ec5ff70536252b2e96e725c/src/system/packages/brew/cask/state.rs#L1074-L1110","documentation":"Cask binary targets must be symlinks living under an allowed binary target root (e.g. a Homebrew bin dir) that resolve back into the cask's staged version directory. If a recorded binary target is not a Symlink-kind record, sits outside allowed roots, or its symlink no longer resolves below candidate.version_dir, mise refuses to prune — deleting would either break a foreign link or remove a file mise does not own.","triggerScenarios":"Calling cask_prune_plan_from_tokens or apply_cask_prune_plan_in when a receipt.binaries path was replaced by a real file (not a symlink), the symlink points outside the cask's version_dir (e.g. into a different version or a manually managed location), or the binary was installed to a nonstandard prefix outside allowed_binary_target_roots().","commonSituations":"User replaced the symlink with a copied binary or their own wrapper script; brew or the user relinked the binary to another cask version; PATH tooling rewrote links in /usr/local/bin; custom HOMEBREW_PREFIX so binaries sit outside the roots this mise recognizes.","solutions":["Reinstall the cask with mise so the binary symlink is recreated pointing into the correct version dir: mise uninstall brew-cask:foo && mise install brew-cask:foo","Inspect the binary path (ls -l) and restore it to a symlink resolving into the cask's Caskroom version directory before pruning","Ensure the binary lives under an allowed binary root for the active Homebrew prefix; align HOMEBREW_PREFIX between the installing and pruning environments","Leave that cask out of the prune plan and manage its binaries via brew"],"exampleFix":"// before: symlink replaced by a copied binary\n$ rm /usr/local/bin/foo && cp ~/staging/foo /usr/local/bin/foo\n// after: restore owned symlink into the version dir\nln -sf \"$(mise --prefix brew-cask:foo)/Caskroom/foo/1.2.3/foo.bin\" /usr/local/bin/foo","handlingStrategy":"validation","validationCode":"// pre-flight: each binary target must be a symlink into the version dir\nfn binaries_are_owned_symlinks(receipt: &CaskReceipt, version_dir: &Path) -> bool {\n    let roots = allowed_binary_target_roots();\n    receipt.binaries.iter().all(|p| {\n        p.symlink_metadata().map(|m| m.file_type().is_symlink()).unwrap_or(false)\n            && roots.iter().any(|r| path_is_below(p, r))\n            && symlink_resolves_below(p, version_dir)\n    })\n}","typeGuard":"fn is_owned_caskroom_symlink(path: &Path, version_dir: &Path) -> bool {\n    path.symlink_metadata().map(|m| m.file_type().is_symlink()).unwrap_or(false)\n        && symlink_resolves_below(path, version_dir)\n}","tryCatchPattern":"match apply_cask_prune_plan_in(&plan) {\n    Ok(removed) => info!(\"pruned {removed} casks\"),\n    Err(e) if e.to_string().contains(\"not an owned Caskroom symlink\") => {\n        warn!(\"binary link replaced externally; reinstalling cask: {e:#}\");\n        // recreate the symlink or fall back to brew management\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Never replace cask-managed bin symlinks with copies or wrapper scripts","Keep the Homebrew prefix consistent between install and prune environments","Use mise uninstall/install to change versions instead of relinking binaries by hand","Run ls -l on receipt.binaries paths before pruning to confirm they are symlinks into the Caskroom"],"tags":["brew","cask","symlink","validation","filesystem"],"backgroundTag":"invalid-argument-value","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"}