jdx/mise · error

brew-cask: app target contains NUL

Error message

brew-cask: app target contains NUL

What it means

`app_target_path` validates the destination path for an app artifact before any filesystem work. If the target name contains a NUL byte (`\0`), which no Unix path can contain, the function bails immediately. This is an early input-validation guard against unusable or malicious path strings.

Solutions

  1. Inspect the app target string for non-printable bytes (e.g. `grep -P '\\x00'` or `xxd`) in your config or the cask definition and remove/repair it.
  2. Re-write the affected config value by hand rather than pasting, to eliminate invisible control characters.
  3. If the value comes from a downloaded cask definition, refresh it or pin a known-good cask version.

Example fix

// before (target read from corrupted source contains \0)
let target = String::from_utf8_lossy(raw_bytes).to_string();

// after (strip NUL/control bytes before use)
let target: String = raw.chars().filter(|c| !c.is_control()).collect();
Defensive patterns

Strategy: validation

Validate before calling

if target_name.contains('\0') {
    return Err("app target contains NUL byte".into());
}

Type guard

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

Try / catch

if let Err(e) = app_target_path(&target_name) {
    if e.to_string().contains("NUL") {
        // sanitize or reject the input before retrying
    }
}

Prevention

When it happens

Trigger: Calling any of `installed_skip_reason`, `app_target_paths`, `install_app`, `validate_adoptable_apps`, or `appdir_artifact_source` with an app target string containing an embedded NUL byte — typically from corrupted config, hostile cask metadata, or a bad string decode.

Common situations: Hand-edited mise.toml or a cask override where a pasted value includes a hidden NUL; data read from a binary-corrupted file; an attacker-supplied cask name probing path handling.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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

Appendix: source

Thrown at src/system/packages/brew/cask/paths.rs:115

        };
        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
}

pub(super) 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 533346cc37)