jdx/mise · error

invalid tap formula name '{name}'

Error message

invalid tap formula name '{name}'

What it means

validate_name rejects tap formula/cask names that are empty, contain path separators ('/', '\\', NUL), equal '.' or '..', or whose PathBuf representation is not exactly one component. This guards against path traversal and malformed names being used to construct file paths inside the tap checkout.

Source

Thrown at src/system/packages/brew/tap.rs:364

    ];
    let mut last_error = None;
    for path in paths {
        match HTTP_FETCH.get_text(format!("{raw_base}/{path}")).await {
            Ok(source) => return Ok((source, path)),
            Err(err) => last_error = Some(err),
        }
    }
    Err(last_error.unwrap()).wrap_err_with(|| format!("tap has no {directory}/{name}.rb"))
}

fn validate_name(name: &str) -> Result<()> {
    if name.is_empty()
        || name.contains(['/', '\\', '\0'])
        || name == "."
        || name == ".."
        || PathBuf::from(name).components().count() != 1
    {
        bail!("invalid tap formula name '{name}'");
    }
    Ok(())
}

#[cfg(test)]
mod tests {
    use super::*;

    async fn test_ruby() -> Result<Option<PathBuf>> {
        if let Some(ruby) = usable_system_ruby().await {
            return Ok(Some(ruby));
        }
        super::super::source::installed_ruby_bin().await
    }

    #[test]
    fn rejects_unsafe_formula_names() {
        for name in ["", ".", "..", "../oops", "a/b", "a\\b"] {

View on GitHub (pinned to afd2eddd3a)

Solutions

  1. Pass only the bare formula/cask file stem (no directories, no tap prefix).
  2. Strip the tap name and directory components before calling, e.g. take the file_stem of the .rb path.
  3. Reject or sanitize input containing '/' or '\\' before invoking.
  4. If the name comes from an untrusted tap, treat this as an invalid/tampered tap and skip or re-clone it.

Example fix

// before
formula_from_ruby(tap, "homebrew/core/wget", ruby_source).await?;
// after
formula_from_ruby(tap, "wget", ruby_source).await?;
Defensive patterns

Strategy: validation

Validate before calling

fn is_valid_tap_formula_name(name: &str) -> bool {
    !name.is_empty()
        && !name.contains(['/', '\\', '\0'])
        && name != "."
        && name != ".."
        && std::path::Path::new(name).components().count() == 1
}

Type guard

fn as_bare_formula_name(s: &str) -> Option<&str> {
    let n = std::path::Path::new(s).file_name()?.to_str()?;
    let n = n.strip_suffix(".rb").unwrap_or(n);
    if n.is_empty() || n == "." || n == ".." { None } else { Some(n) }
}

Try / catch

match formula_from_ruby(tap, name, src).await {
    Err(e) if e.to_string().starts_with("invalid tap formula name") => {
        eprintln!("skipping malformed entry: {name}");
        Ok(None)
    }
    other => other.map(Some),
}

Prevention

When it happens

Trigger: formula_from_ruby or cask_from_ruby is given a name extracted from a tap's file path or user request that is empty, includes slashes/backslashes, is '.'/'..', or otherwise spans multiple path components.

Common situations: A formula name passed as 'user/repo/formula' instead of just 'formula'; malicious or corrupted tap file names containing '..' or separators; misparsed Ruby filenames; passing a fully qualified tap+name string where only the bare name is expected.

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@afd2eddd3a (2026-09-09). Data as JSON: /api/errors/c743010e65aebd84. Report an issue: GitHub.