jdx/mise · error

brew-cask: : invalid path

Error message

brew-cask:{}: invalid {kind} {field} path {}

What it means

When parsing a Homebrew cask's flight-plan artifact step (e.g. binary, pkg, or artifact move directives), each path must be a relative, well-formed path inside the staged area. `parse_flight_path` throws this error when `validate_flight_relative_path` rejects the `path` string in the cask's JSON artifact entry. It guards against absolute paths, `..` traversal, and other path components that would move files outside the staging area.

Solutions

  1. Inspect the cask JSON artifact entry and rewrite `path` as a plain relative path (no leading '/', no '..') that stays inside the staged area
  2. Report or fix the offending cask in its tap if upstream data is malformed
  3. If the path is legitimately external, use a different artifact kind/directive that supports it rather than a staged relative path

Example fix

// before (cask artifact JSON)
{ "type": "binary", "path": "/opt/homebrew/bin/foo" }
// after
{ "type": "binary", "path": "foo.app/Contents/MacOS/foo" }
Defensive patterns

Strategy: validation

Validate before calling

// Rust: validate a cask artifact path before parsing
fn is_safe_relative_path(p: &str) -> bool {
    !p.is_empty()
        && !p.starts_with('/')
        && std::path::Path::new(p)
            .components()
            .all(|c| matches!(c, std::path::Component::Normal(_)))
}
if !is_safe_relative_path(&artifact["path"].as_str().unwrap_or_default()) {
    eprintln!("artifact path must be a clean relative path");
}

Type guard

fn valid_flight_path(p: &&str) -> bool {
    std::path::Path::new(p)
        .components()
        .all(|c| matches!(c, std::path::Component::Normal(_)))
}

Prevention

When it happens

Trigger: Calling parse_flight_path (via FlightStep::Move or parse_flight_step) on a cask JSON artifact whose `path` value fails validate_flight_relative_path — e.g. an absolute path like "/usr/local/bin/foo", a path containing "..", or an empty/rooted path.

Common situations: A third-party tap publishes a cask whose artifact stanza uses absolute paths or paths escaping the staged_path; a hand-edited or generated cask JSON; a Homebrew upstream format change producing paths this parser intentionally rejects.

Understand the failure class

Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.

Related errors


AI-assisted analysis of jdx/mise@533346cc37 (2026-09-17). Data as JSON: /api/errors/4397af13e9fa600c. Report an issue: GitHub.

Appendix: source

Thrown at src/system/packages/brew/cask/artifacts.rs:1125

            "brew-cask:{}: unsupported {kind} {field} metadata format",
            cask.token
        )
    })?;
    let base = match object.get("base").and_then(Value::as_str) {
        Some("staged_path") => FlightPathBase::StagedPath,
        Some(base) => bail!(
            "brew-cask:{}: unsupported {kind} {field} base {}",
            cask.token,
            base
        ),
        None => bail!("brew-cask:{}: unsupported {kind} {field} base", cask.token),
    };
    let path = object
        .get("path")
        .and_then(Value::as_str)
        .ok_or_else(|| eyre!("brew-cask:{}: unsupported {kind} {field} path", cask.token))?;
    if validate_flight_relative_path(path).is_err() {
        bail!(
            "brew-cask:{}: invalid {kind} {field} path {}",
            cask.token,
            path
        )
    }
    Ok(FlightPath {
        base,
        path: path.to_string(),
    })
}

/// `set_permissions` paths follow Homebrew's `remove` shape but may also
/// name the installed app for `postflight_steps`, so `appdir` is accepted
/// beside `staged_path`.
pub(super) fn parse_permissions_flight_path(
    cask: &Cask,
    kind: &str,
    value: Option<&Value>,

View on GitHub (pinned to 533346cc37)