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 thanView on GitHub (pinned to 9dcfcaa0dc)
Solutions
- Inspect the cask definition (`brew info --json=v2 --cask <token>` plus the tap source) for a corrupted artifact target string
- Remove the suspect tap (`brew untap <tap>`) if the malformed target comes from a third-party source
- Clear mise's cached cask data (`mise cache clear`) and the stale receipt, then retry
- 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
- Sanitize any programmatically generated target strings before storing them in cask overrides
- Treat NUL-in-path errors as data corruption signals — investigate the tap/cache rather than retrying
- Keep cask JSON sources limited to trusted taps
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
- brew-cask: binary target contains NUL
- brew-cask: app target '{target_name}' must not contain '..'
- mise upgrade --monorepo is not implemented yet
- brew-cask: refusing generic artifact copy outside Homebrew p
- brew-cask: invalid generic artifact parent
AI-assisted analysis of jdx/mise@9dcfcaa0dc (2026-08-17).
Data as JSON: /api/errors/49f406ef51a5df8b.
Report an issue: GitHub.