jdx/mise · error

brew-cask: command_wrapper requires a command name without p

Error message

brew-cask: command_wrapper requires a command name without path components

What it means

This error is thrown by parse_command_wrapper_artifact when a Homebrew cask `command_wrapper` artifact declares a command name that contains path components (e.g. 'bin/tool' or './tool'). The library requires a bare executable name so the wrapper can be installed under a single file name in the command directory.

Source

Thrown at src/system/packages/brew/cask/artifacts.rs:191

pub(super) fn parse_command_wrapper_artifact(
    value: &Value,
) -> Result<Option<CommandWrapperArtifact>> {
    let Some(wrapper) = value.as_object().and_then(|o| o.get("command_wrapper")) else {
        return Ok(None);
    };
    let values = wrapper
        .as_array()
        .ok_or_else(|| eyre!("brew-cask: command_wrapper metadata must be an array"))?;
    let name = values
        .first()
        .and_then(Value::as_str)
        .ok_or_else(|| eyre!("brew-cask: command_wrapper requires a command name"))?;
    let name_path = Path::new(name);
    if name_path.file_name().and_then(|name| name.to_str()) != Some(name)
        || matches!(name, "." | "..")
    {
        bail!("brew-cask: command_wrapper requires a command name without path components");
    }
    let options = values
        .get(1)
        .and_then(Value::as_object)
        .ok_or_else(|| eyre!("brew-cask: command_wrapper requires options"))?;
    let mut unsupported = options
        .keys()
        .filter(|key| !matches!(key.as_str(), "content" | "executable" | "args" | "env"))
        .cloned()
        .collect::<Vec<_>>();
    unsupported.sort();
    if !unsupported.is_empty() {
        bail!(
            "brew-cask: command_wrapper has unsupported option {}",
            unsupported.join(", ")
        );
    }
    let content = options

View on GitHub (pinned to afd2eddd3a)

Solutions

  1. Use only the bare command/file name without '/' or '.' components, e.g. 'mytool' instead of 'bin/mytool'.
  2. Verify the name is not '.' or '..'.
  3. If the executable lives in a subdirectory, express that elsewhere (e.g. in the executable/content options) and keep name as the final component.

Example fix

// before
"command_wrapper" => json!(["bin/mytool", {"executable": "mytool"}])
// after
"command_wrapper" => json!(["mytool", {"executable": "mytool"}])
Defensive patterns

Strategy: validation

Validate before calling

fn valid_cw_name(name: &str) -> bool {
    let p = std::path::Path::new(name);
    p.file_name().and_then(|f| f.to_str()) == Some(name) && !matches!(name, "." | "..")
}
assert!(valid_cw_name("mytool"));

Type guard

fn valid_cw_name(name: &str) -> bool {
    std::path::Path::new(name)
        .file_name()
        .and_then(|f| f.to_str())
        == Some(name)
        && !matches!(name, "." | "..")
}

Prevention

When it happens

Trigger: Parsing a cask artifact stanza whose command_wrapper `name` value is a string containing '/' or path separators, is '.' or '..', or whose final path component does not equal the whole string.

Common situations: Copy-pasting an executable path from a Homebrew formula or absolute install path into the command_wrapper name field; authoring a cask definition by hand and using 'bin/foo' instead of 'foo'.

Understand the failure class

Background: "invalid id" errors: invalid identifier format — why libraries reject IDs before lookup, and how to fix them — this error's family across 37 libraries.

Related errors


AI-assisted analysis of jdx/mise@afd2eddd3a (2026-09-09). Data as JSON: /api/errors/2045b2cb6bd3a54a. Report an issue: GitHub.