jdx/mise · error
brew-cask: structured set_permissions must use staged_path…
Error message
brew-cask: structured set_permissions must use staged_path or appdir
What it means
A structured set_permissions flight step must resolve its path against either the staged cask directory or the appdir; any other FlightPathBase is rejected by permissions_flight_paths. Restricting chmod-style operations to these bases prevents a cask from altering permissions on arbitrary filesystem locations.
Solutions
- Change the set_permissions path base to "staged_path" or "appdir" in the flight definition.
- If the target truly lives outside those trees, the operation is not supported — perform the permission change out-of-band (post-install script) instead.
- Validate the cask's flight config against the supported FlightPathBase values before installing.
Example fix
// before
{ "set_permissions": { "path": { "base": "absolute", "path": "/usr/local/bin/tool" }, "mode": "0755" } }
// after
{ "set_permissions": { "path": { "base": "staged_path", "path": "Tool.app/Contents/MacOS/tool" }, "mode": "0755" } } Defensive patterns
Strategy: validation
Validate before calling
function validatePermissionsBase(step) {
const allowed = ['staged_path', 'appdir'];
if (!allowed.includes(step.set_permissions.path.base)) {
throw new Error(`set_permissions base must be one of ${allowed}, got '${step.set_permissions.path.base}'`);
}
} Prevention
- Restrict set_permissions paths to staged_path or appdir bases.
- Perform out-of-tree permission changes with a separate post-install step, not flight stanzas.
- Lint cask flight configs before publishing or installing them.
When it happens
Trigger: execute_flight_step processes a set_permissions step; permissions_flight_paths matches the path's base against staged_path/appdir variants and hits the _ wildcard arm, bailing — e.g. base set to an absolute/custom path value.
Common situations: A hand-written cask flight config sets a permissions path with a base other than staged_path or appdir; a config was edited or migrated incorrectly; copying a stanza from another tool that allows absolute paths.
Understand the failure class
Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.
Related errors
- brew-cask: binary target
- brew-cask: invalid appdir
- brew-cask: refusing elevated operation through mutable…
- brew-cask: refusing elevated operation through mutable…
- brew-cask: refusing operation through untrusted directory
AI-assisted analysis of jdx/mise@533346cc37 (2026-09-17).
Data as JSON: /api/errors/c737a5c4998bd4a6.
Report an issue: GitHub.
Appendix: source
Thrown at src/system/packages/brew/cask/flight.rs:1083
staged_path: &Path,
appdir: &Path,
) -> Result<Vec<PathBuf>> {
match path.base {
FlightPathBase::StagedPath if is_flight_glob(&path.path) => {
// Like remove steps, set_permissions has no glob flag; Homebrew
// globs the path syntax itself.
let pattern = expand_flight_template(cask, &path.path, staged_path, appdir);
expand_staged_glob(staged_path, &pattern)
}
FlightPathBase::StagedPath | FlightPathBase::AppDir => {
Ok(vec![resolve_flight_path_with_context(
cask,
path,
staged_path,
appdir,
)?])
}
_ => bail!("brew-cask: structured set_permissions must use staged_path or appdir"),
}
}
pub(super) fn expand_staged_glob(staged_path: &Path, pattern: &str) -> Result<Vec<PathBuf>> {
let mut matches = Vec::new();
let escaped_root = glob::Pattern::escape(staged_path.to_string_lossy().as_ref());
for pattern in expand_braces(pattern) {
validate_flight_relative_path(&pattern)?;
let rooted_pattern = Path::new(&escaped_root)
.join(Path::new(&pattern))
.to_string_lossy()
.to_string();
for path in glob::glob_with(
&rooted_pattern,
glob::MatchOptions {
require_literal_separator: true,
..Default::default()
},View on GitHub (pinned to 533346cc37)