jdx/mise · error · eyre::Report

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

Error message

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

What it means

After accepting base == "staged_path", mise runs the flight-path object's "path" string through validate_flight_relative_path (src/system/packages/brew/cask.rs:3905), which rejects absolute paths and any '..' component. This bail fires when the declared relative path would escape the staged cask location, so mise refuses before creating any link. It is a containment check: flight paths must stay inside the staged directory they are anchored to.

Source

Thrown at src/system/packages/brew/cask.rs:5872

            "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(),
    })
}

fn collect_pkg_receipt_ids(value: &Value, pkg_ids: &mut Vec<String>) {
    let Some(object) = value.as_object() else {
        return;
    };
    let Some(metadata) = object.get("uninstall") else {
        return;
    };

View on GitHub (pinned to 9dcfcaa0dc)

Solutions

  1. Inspect the cask payload (`brew info --json=v2 --cask <token>`) and confirm the flight-path "path" field is a plain relative path with no leading '/' and no '..' segments
  2. If the cask is from a third-party tap, report/fix the artifact stanza upstream or remove the tap
  3. Clear mise's cached cask JSON (`mise cache clear`) and re-fetch in case the copy is corrupted
  4. Update mise in case a newer release supports the artifact form this cask uses
Defensive patterns

Strategy: type-guard

Type guard

use std::path::{Component, Path};
fn is_valid_flight_path_str(p: &str) -> bool {
    let path = Path::new(p);
    !path.is_absolute()
        && !path.components().any(|c| matches!(c, Component::ParentDir))
        && !p.contains('\0')
}

Try / catch

match parse_flight_path(&value) {
    Ok(fp) => fp,
    Err(e) if e.to_string().contains("invalid") && e.to_string().contains("path") => {
        warn!("rejecting unsafe flight path in cask artifact");
        continue;
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: A cask artifact flight-path object whose "path" starts with '/' (e.g. "/Applications/Foo.app") or contains a ParentDir segment (e.g. "../Foo.app") reaching this parser during install/upgrade.

Common situations: Hand-edited or malformed cask definitions in a tap; corrupted cached cask JSON; a malicious or typosquatted tap attempting to link outside the staged path.

Related errors


AI-assisted analysis of jdx/mise@9dcfcaa0dc (2026-08-17). Data as JSON: /api/errors/663879c21f88fb6e. Report an issue: GitHub.