jdx/mise · error · eyre::Report

brew-cask: app target contains NUL

Error message

brew-cask: app target contains NUL

What it means

app_target_path converts a cask 'app' artifact target name into the PathBuf used for (possibly privileged) linking into the app dir. Before any filesystem work it rejects target names containing a NUL byte, because NUL cannot appear in a valid filename and would truncate the path at the OS syscall boundary. Seeing this error almost always means the cask JSON or receipt is corrupted or deliberately crafted.

Source

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

        };
        let matches = match (a, b) {
            (Component::Normal(a), Component::Normal(b)) => match (a.to_str(), b.to_str()) {
                (Some(a), Some(b)) => a.eq_ignore_ascii_case(b),
                _ => a == b,
            },
            _ => a == b,
        };
        if !matches {
            return false;
        }
    }
    true
}

fn app_target_path(target_name: &str) -> Result<PathBuf> {
    let app_dir = target_app_dir()?;
    if target_name.contains('\0') {
        bail!("brew-cask: app target contains NUL");
    }
    if target_name.contains('/') {
        let target = target_name.replace("$HOMEBREW_PREFIX", &prefix::prefix().to_string_lossy());
        let path = PathBuf::from(target);
        if path
            .components()
            .any(|component| matches!(component, Component::ParentDir))
        {
            bail!("brew-cask: app target '{target_name}' must not contain '..'");
        }
        if path.is_absolute() {
            let prefix_app_dir = prefix::prefix().join("Applications");
            if path.starts_with(&app_dir) || path.starts_with(&prefix_app_dir) {
                return Ok(path);
            }
            // Casks routinely hardcode an absolute `/Applications/Foo.app`
            // target. When an override appdir is configured, relocate such a
            // target into it (preserving any subdirectories) rather than

View on GitHub (pinned to 9dcfcaa0dc)

Solutions

  1. Inspect the cask definition (`brew info --json=v2 --cask <token>` plus the tap source) for a corrupted artifact target string
  2. Remove the suspect tap (`brew untap <tap>`) if the malformed target comes from a third-party source
  3. Clear mise's cached cask data (`mise cache clear`) and the stale receipt, then retry
  4. Update mise — security hardening and parser fixes land regularly
Defensive patterns

Strategy: type-guard

Type guard

fn is_clean_app_target(name: &str) -> bool {
    !name.contains('\0')
}

Try / catch

match app_target_path(name) {
    Ok(p) => p,
    Err(e) if e.to_string().contains("contains NUL") => {
        warn!("dropping corrupted app target {name:?}");
        return Ok(None);
    }
    Err(e) => Err(e),
}

Prevention

When it happens

Trigger: A cask 'app' artifact target string (from cask JSON, tap data, or a stored receipt) containing '\0' reaching app_target_path during install, upgrade, or prune.

Common situations: Corrupted cask cache or partially-written receipt JSON; a malicious/typosquatted tap trying path injection; binary garbage ending up in a tap's artifact stanza.

Related errors


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