jdx/mise · error · eyre::Report
brew-cask: binary target '{}' must not contain '..'
Error message
brew-cask: binary target '{}' must not contain '..' What it means
binary_target_path expands $HOMEBREW_PREFIX, anchors relative targets under the brew prefix (or prefix/bin for bare names), then rejects any result containing a Component::ParentDir ('..'). This prevents a binary target from escaping the allowed install roots after expansion and anchoring.
Source
Thrown at src/system/packages/brew/cask.rs:6165
if target_name.contains("$APPDIR") {
bail!("brew-cask: $APPDIR must prefix a binary target");
}
let prefix = prefix::prefix();
let prefix_str = prefix.to_string_lossy();
let target_name = target_name.replace("$HOMEBREW_PREFIX", prefix_str.as_ref());
let path = PathBuf::from(&target_name);
let target = if path.is_absolute() {
path
} else if target_name.contains('/') {
prefix.join(path)
} else {
prefix.join("bin").join(path)
};
if target
.components()
.any(|component| matches!(component, Component::ParentDir))
{
bail!(
"brew-cask: binary target '{}' must not contain '..'",
target.display()
);
}
let roots = allowed_binary_target_roots();
if !roots.iter().any(|root| target.starts_with(root)) {
bail!(
"brew-cask: binary target '{}' must be under {}",
target.display(),
allowed_binary_target_roots_display(&roots)
);
}
Ok(target)
}
fn installed_version(token: &str) -> Option<String> {
let versions = installed_versions(token);
match versions.as_slice() {View on GitHub (pinned to 9dcfcaa0dc)
Solutions
- Use a clean target: bare "tool" (goes to <prefix>/bin), "sbin/tool" (goes to <prefix>/sbin), or "$HOMEBREW_PREFIX/..." without '..'
- Report/fix the malformed artifact stanza in the tap
- Verify with `brew info --json=v2 --cask <token>` what target is actually published
Example fix
// before (cask binary target) "target": "../sbin/tool" // after "target": "sbin/tool"
Defensive patterns
Strategy: type-guard
Type guard
use std::path::{Component, Path};
fn binary_target_has_no_dotdot(name: &str, homebrew_prefix: &str) -> bool {
let expanded = name.replace("$HOMEBREW_PREFIX", homebrew_prefix);
!Path::new(&expanded)
.components()
.any(|c| matches!(c, Component::ParentDir))
} Try / catch
match binary_target_path(name, &appdir) {
Ok(p) => p,
Err(e) if e.to_string().contains("must not contain '..'") => {
warn!("skipping binary target with '..': {name}");
continue;
}
Err(e) => Err(e),
} Prevention
- Express binary targets as bare names or prefix-relative paths without '..'
- Expand $HOMEBREW_PREFIX yourself when linting cask targets — traversal after expansion is what is checked
When it happens
Trigger: A binary target like "../sbin/tool", "$HOMEBREW_PREFIX/../usr/bin/tool", or any target that yields a '..' component after expansion/anchoring.
Common situations: Malformed tap casks; hand-edited cask overrides trying to redirect binaries outside the prefix; templated targets that concatenate '..' fragments.
Related errors
- brew-cask:{}: invalid {kind} {field} path {}
- brew-cask: app target '{target_name}' must not contain '..'
- brew-cask: binary $APPDIR target '{target_name}' must stay b
- brew-cask: $APPDIR must prefix a binary target
- mise upgrade --monorepo is not implemented yet
AI-assisted analysis of jdx/mise@9dcfcaa0dc (2026-08-17).
Data as JSON: /api/errors/e948ac00b3dc8584.
Report an issue: GitHub.