jdx/mise · error

brew-cask: invalid {kind} '{value}'

Error message

brew-cask: invalid {kind} '{value}'

What it means

Defense-in-depth path validation applied to the requested token, the API token from the cask JSON, and its version: the value must be a single normal path component — non-empty, no NUL bytes, no '/' or '..' components — and must not equal the reserved '.metadata' marker or start with '.mise-' (mise's bookkeeping names). Any violation aborts before the value is ever joined into a filesystem path.

Source

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

    if cask.token != requested_token && !trusted_alias {
        bail!(
            "brew-cask: requested token '{requested_token}' does not match API token '{}'",
            cask.token
        );
    }
    Ok(())
}

fn validate_cask_path_component(kind: &str, value: &str) -> Result<()> {
    let mut components = Path::new(value).components();
    let valid = !value.is_empty()
        && !value.contains('\0')
        && matches!(components.next(), Some(Component::Normal(_)))
        && components.next().is_none()
        && value != ".metadata"
        && !value.starts_with(".mise-");
    if !valid {
        bail!("brew-cask: invalid {kind} '{value}'");
    }
    Ok(())
}

async fn fetch_and_stage(cask: &Cask, pr: Option<&dyn SingleReport>) -> Result<PathBuf> {
    if cask.url.ends_with(".git") {
        return fetch_git_clone_and_stage(cask, pr).await;
    }
    let archive = fetch_archive(cask, pr).await?;
    extract_archive(cask, &archive, pr)
}

async fn fetch_git_clone_and_stage(cask: &Cask, pr: Option<&dyn SingleReport>) -> Result<PathBuf> {
    let extract_dir = crate::dirs::CACHE
        .join("system-brew")
        .join("cask-extract")
        .join(format!("{}-{}", cask.token, cask.version));
    file::remove_all(&extract_dir)?;

View on GitHub (pinned to 9dcfcaa0dc)

Solutions

  1. Use plain alphanumeric/dash tokens when requesting casks (the cask's filename in its tap)
  2. If you maintain the tap, fix token/version fields to be single path components
  3. If you don't control the metadata, do not install that cask — the guard is protecting you
Defensive patterns

Strategy: validation

Validate before calling

fn valid_cask_component(value: &str) -> bool {
    use std::path::{Component, Path};
    let mut c = Path::new(value).components();
    !value.is_empty()
        && !value.contains('\0')
        && matches!(c.next(), Some(Component::Normal(_)))
        && c.next().is_none()
        && value != ".metadata"
        && !value.starts_with(".mise-")
}

Type guard

fn is_safe_cask_token(token: &str) -> bool {
    !token.is_empty() && !token.contains('/') && !token.contains('\0')
        && !token.starts_with('.') && token != ".metadata" && !token.contains("..")
}

Try / catch

Catch the 'invalid {kind}' bail and reject the offending request/tap metadata immediately; never sanitize and continue — a bad token or version means the metadata is untrustworthy.

Prevention

When it happens

Trigger: A user requests a cask name containing slashes or '..' (brew-cask:../evil), or a malicious/corrupted tap publishes cask JSON whose token or version embeds path separators or claims the reserved '.metadata' name — which could otherwise escape the Caskroom or collide with Homebrew's marker.

Common situations: Script-generated config with unescaped names; hand-edited third-party taps; supply-chain probing of mise's cask pipeline.

Related errors


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