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

  1. Change the set_permissions path base to "staged_path" or "appdir" in the flight definition.
  2. If the target truly lives outside those trees, the operation is not supported — perform the permission change out-of-band (post-install script) instead.
  3. 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

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


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)