{"record":{"id":"802f47f6c19b57e9","repo":"jdx/mise","slug":"invalid-opt-record-for-brew-name-at-target-must-be-a","errorCode":null,"errorMessage":"invalid opt record for brew:{name} at {}: target {} must be a directory directly inside {}; inspect it and restore the formula's correct opt link","messagePattern":"invalid opt record for brew:(.+?) at (.+?): target (.+?) must be a directory directly inside (.+?); inspect it and restore the formula's correct opt link","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/system/packages/brew/pour.rs","lineNumber":84,"sourceCode":"    };\n    let opt = prefix.join(\"opt\").join(name);\n    let rack = prefix.join(\"Cellar\").join(name);\n    let metadata =\n        std::fs::symlink_metadata(&opt).map_err(|err| package_root_io_error(name, &opt, err))?;\n    if !metadata.is_symlink() {\n        bail!(\n            \"invalid opt record for brew:{name} at {}: expected a symbolic link; inspect it and restore the formula's correct opt link\",\n            opt.display()\n        );\n    }\n    let target =\n        std::fs::canonicalize(&opt).map_err(|err| package_root_io_error(name, &opt, err))?;\n    let canonical_rack =\n        std::fs::canonicalize(&rack).map_err(|err| package_root_io_error(name, &rack, err))?;\n    let metadata =\n        std::fs::metadata(&target).map_err(|err| package_root_io_error(name, &target, err))?;\n    if !metadata.is_dir() || target.parent() != Some(canonical_rack.as_path()) {\n        bail!(\n            \"invalid opt record for brew:{name} at {}: target {} must be a directory directly inside {}; inspect it and restore the formula's correct opt link\",\n            opt.display(),\n            target.display(),\n            canonical_rack.display()\n        );\n    }\n    Ok(opt)\n}\n\n/// Retain the filesystem error while adding lookup context and actionable recovery guidance.\nfn package_root_io_error(name: &str, path: &Path, err: std::io::Error) -> eyre::Report {\n    let context = if err.kind() == std::io::ErrorKind::NotFound {\n        format!(\n            \"brew:{name} has no usable installed opt link: {}; install or reconcile it with `mise bootstrap packages apply brew:{name}`\",\n            path.display()\n        )\n    } else {\n        format!(","sourceCodeStart":66,"sourceCodeEnd":102,"githubUrl":"https://github.com/jdx/mise/blob/533346cc374382b41ec5ff70536252b2e96e725c/src/system/packages/brew/pour.rs#L66-L102","documentation":"After confirming `opt/<formula>` is a symlink, strict_package_root canonicalizes it and requires the target to be a directory whose parent is exactly the formula's Cellar rack (`Cellar/<formula>`). This proves the opt link points at a real keg inside this prefix's Cellar. A dangling target, a target outside Cellar, or a versioned directory elsewhere (e.g. into another prefix, or a file) makes the record invalid.","triggerScenarios":"The opt symlink resolves but its canonicalized target is not a directory directly inside Cellar/<name> — e.g. link points into another Homebrew prefix, a relocated/stale path, a version directory that was moved, or a file instead of a keg directory.","commonSituations":"Prefixes migrated or symlinked between locations leaving stale absolute targets; manually relinking opt to an extracted tarball outside Cellar; upgrading tools that moved the keg.","solutions":["Inspect the link target: `readlink -f $(brew --prefix)/opt/<name>` and compare with `ls $(brew --prefix)/Cellar/<name>/`","Remove and recreate the link to the keg actually in Cellar: `ln -sfn ../Cellar/<name>/<version> $(brew --prefix)/opt/<name>`","If the keg is genuinely missing, re-apply the package: `mise bootstrap packages apply brew:<name>`"],"exampleFix":"# before: opt/python -> /opt/old-brew/Cellar/python/3.12 (foreign prefix)\nln -sfn \"../Cellar/python/3.13.2\" \"$(brew --prefix)/opt/python\"","handlingStrategy":"validation","validationCode":"t=$(readlink -f \"$(brew --prefix)/opt/$name\")\ncase \"$t\" in\n  \"$(brew --prefix)/Cellar/$name\"/*) ;;\n  *) echo \"opt/$name points outside Cellar/$name: $t\" ;;\nesac","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Never hand-point opt/<name> at directories outside Cellar/<name>","Recreate opt links after moving or symlinking the brew prefix (targets must canonicalize inside the rack)","Verify with `readlink -f` after any manual prefix surgery"],"tags":["brew","symlink","corrupt-state"],"backgroundTag":"broken-symlink","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"}