jdx/mise · error
brew-cask: generic artifact target '{}' must stay below {}
Error message
brew-cask: generic artifact target '{}' must stay below {} What it means
generic_artifact_target_path expands $HOMEBREW_PREFIX in the cask's target string and validates the result: it must be absolute, lexically under the prefix with at least one component beneath it, free of '..' components, and its symlink-resolved root must still be under the prefix. Any violation refuses with the offending target shown.
Source
Thrown at src/system/packages/brew/cask.rs:2375
run_installer_artifact(stage, installer, targets.copied_files())?;
completed(index)?;
}
durabilize_staged_symlink_targets(stage, temporary_caskroom, targets)
}
fn generic_artifact_target_path(target: &str) -> Result<PathBuf> {
let prefix = prefix::prefix();
let expanded = target.replace("$HOMEBREW_PREFIX", &prefix.to_string_lossy());
let target = PathBuf::from(expanded);
if !target.is_absolute()
|| !target.starts_with(&prefix)
|| target.strip_prefix(&prefix)?.components().next().is_none()
|| target
.components()
.any(|component| matches!(component, Component::ParentDir))
|| !path_starts_with_resolved_root(&target, &prefix)
{
bail!(
"brew-cask: generic artifact target '{}' must stay below {}",
target.display(),
prefix.display()
);
}
Ok(target)
}
fn generic_artifact_targets(artifacts: &CaskArtifacts) -> Result<Vec<PathBuf>> {
artifacts
.generic
.iter()
.map(|artifact| generic_artifact_target_path(&artifact.target))
.collect()
}
fn previous_generic_targets(cask: &Cask) -> Result<Vec<CaskTargetRecord>> {
let Some(version) = installed_version(&cask.token) else {View on GitHub (pinned to 9dcfcaa0dc)
Solutions
- Write the target as an absolute path beginning with $HOMEBREW_PREFIX ("$HOMEBREW_PREFIX/Library/Foo")
- Remove '..' components from the target string
- Make the prefix a real directory or ensure its symlinks resolve consistently so the resolved-root check passes
Example fix
# before target: "Library/Application Support/Foo" # after target: "$HOMEBREW_PREFIX/Library/Application Support/Foo"
Defensive patterns
Strategy: validation
Validate before calling
use std::path::{Path, Component};
fn target_string_is_valid(target: &str, prefix: &Path) -> bool {
let expanded = target.replace("$HOMEBREW_PREFIX", &prefix.to_string_lossy());
let t = Path::new(&expanded);
t.is_absolute()
&& t.starts_with(prefix)
&& t.strip_prefix(prefix).is_ok_and(|r| r.components().next().is_some())
&& !t.components().any(|c| matches!(c, Component::ParentDir))
} Prevention
- Always write generic artifact targets as "$HOMEBREW_PREFIX/..." absolute paths
- Keep '..' out of target strings
- Ensure the prefix resolves consistently (no retargeted symlinks) across operations
When it happens
Trigger: A target string that is relative ("Library/Foo"), absolute outside the prefix ("/Library/Foo"), contains '..', or where the prefix itself is a symlink so the resolved root no longer matches (path_starts_with_resolved_root fails).
Common situations: Casks hardcoding absolute macOS paths; HOMEBREW_PREFIX pointed at a symlinked directory; target templates missing the $HOMEBREW_PREFIX variable.
Related errors
- brew-cask: refusing generic artifact copy outside Homebrew p
- brew-cask: refusing to remove generic artifact outside {}: {
- mise upgrade --monorepo is not implemented yet
- brew-cask: invalid generic artifact parent
- brew-cask: refusing installer executable outside trusted ins
AI-assisted analysis of jdx/mise@9dcfcaa0dc (2026-08-17).
Data as JSON: /api/errors/a0117444eb7ace2f.
Report an issue: GitHub.