{"record":{"id":"bfb3e16d2a4640ad","repo":"jdx/mise","slug":"brew-cask-git-only-path-must-name-a-directory","errorCode":null,"errorMessage":"brew-cask:{}: git only_path must name a directory within the checkout","messagePattern":"brew-cask:(.+?): git only_path must name a directory within the checkout","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/system/packages/brew/cask/fetch.rs","lineNumber":227,"sourceCode":"        || only_path\n            .components()\n            .any(|component| matches!(component, Component::ParentDir | Component::Prefix(_)))\n    {\n        bail!(\n            \"brew-cask:{}: git only_path must stay within the checkout\",\n            cask.token\n        );\n    }\n    let clone_root = clone_dir.canonicalize()?;\n    let source = clone_dir.join(only_path).canonicalize().wrap_err_with(|| {\n        format!(\n            \"brew-cask:{}: git only_path does not exist: {}\",\n            cask.token,\n            only_path.display()\n        )\n    })?;\n    if !source.starts_with(&clone_root) || !source.is_dir() {\n        bail!(\n            \"brew-cask:{}: git only_path must name a directory within the checkout\",\n            cask.token\n        );\n    }\n    Ok(source)\n}\n\npub(super) async fn fetch_archive(cask: &Cask, pr: Option<&dyn SingleReport>) -> Result<PathBuf> {\n    let filename = archive_filename(&cask.url)\n        .ok_or_else(|| eyre!(\"brew-cask:{}: URL has no file name\", cask.token))?;\n    let cache_dir = crate::dirs::CACHE.join(\"system-brew\").join(\"casks\");\n    file::create_dir_all(&cache_dir)?;\n    let url_hash = &hash::hash_sha256_to_str(&cask.url)[..12];\n    let archive = cache_dir.join(format!(\n        \"{}-{}-{url_hash}-{filename}\",\n        cask.token, cask.version\n    ));\n    if !archive.exists() {","sourceCodeStart":209,"sourceCodeEnd":245,"githubUrl":"https://github.com/jdx/mise/blob/afd2eddd3a50c16190efc1c7e94404b48f72af57/src/system/packages/brew/cask/fetch.rs#L209-L245","documentation":"After the traversal checks, mise canonicalizes clone_dir/only_path and requires that it exists, stays inside the canonicalized clone root, and is a directory. If the path resolves outside the checkout (e.g. via a symlink) or is not a directory, the git-only_path staging is aborted. Note a missing path raises the sibling 'only_path does not exist' error instead; this one fires for out-of-tree or non-directory targets.","triggerScenarios":"Installing a git-URL cask whose only_path points at a regular file rather than a directory, or at a symlink resolving outside the clone root; also triggered if clone_dir/only_path escapes the checkout after canonicalization.","commonSituations":"A cask authored for an older layout where only_path named a file; repo restructure moved/renamed the directory; a symlinked path in the checkout resolving to an external location.","solutions":["Change only_path to name a directory inside the repository checkout.","If only_path must reference a single file, update the cask definition to stage that file differently (e.g. use an archive URL instead of git).","Verify the directory exists on the branch being cloned (check cask url_specs.branch) and adjust branch or path."],"exampleFix":"// before\n\"only_path\": \"dist/tool.bin\"\n// after (directory containing the artifacts)\n\"only_path\": \"dist\"","handlingStrategy":"validation","validationCode":"// ensure the path exists and is a directory in the cloned repo before install\nconst p = require('child_process');\nconst out = p.execSync(`git ls-tree -d --name-only HEAD ${relPath}`).toString().trim();\nif (!out) throw new Error(`only_path '${relPath}' is not a directory in the repo`);","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Point only_path at directories, not individual files.","Pin the cask's branch and verify the directory exists on that branch.","Re-check only_path after any repository restructure."],"tags":["brew","git","path-validation","directory-not-found"],"backgroundTag":"path-is-not-a-directory","analyzedSha":"afd2eddd3a50c16190efc1c7e94404b48f72af57","analyzedAt":"2026-09-09T01:38:25.179Z","contentChangedAt":"2026-09-09T01:38:25.179Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}