{"record":{"id":"51ca4c6aaec4999f","repo":"jdx/mise","slug":"brew-cask-command-wrapper-requires-content-or-exe-51ca4c","errorCode":null,"errorMessage":"brew-cask: command_wrapper requires content or executable","messagePattern":"brew-cask: command_wrapper requires content or executable","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/system/packages/brew/cask/artifacts.rs","lineNumber":219,"sourceCode":"        .collect::<Vec<_>>();\n    unsupported.sort();\n    if !unsupported.is_empty() {\n        bail!(\n            \"brew-cask: command_wrapper has unsupported option {}\",\n            unsupported.join(\", \")\n        );\n    }\n    let content = options\n        .get(\"content\")\n        .and_then(Value::as_str)\n        .map(str::to_string);\n    let executable = options\n        .get(\"executable\")\n        .and_then(Value::as_str)\n        .map(str::to_string);\n    match (content.is_some(), executable.is_some()) {\n        (false, false) => {\n            bail!(\"brew-cask: command_wrapper requires content or executable\")\n        }\n        (true, true) => {\n            bail!(\"brew-cask: command_wrapper requires content or executable, not both\")\n        }\n        _ => {}\n    }\n    let args = string_args(options, \"command_wrapper\")?;\n    let env = options\n        .get(\"env\")\n        .map(|env| {\n            env.as_object()\n                .ok_or_else(|| eyre!(\"brew-cask: command_wrapper env must be an object\"))?\n                .iter()\n                .map(|(key, value)| {\n                    if !is_shell_env_name(key) {\n                        bail!(\"brew-cask: invalid command_wrapper environment name '{key}'\");\n                    }\n                    value","sourceCodeStart":201,"sourceCodeEnd":237,"githubUrl":"https://github.com/jdx/mise/blob/afd2eddd3a50c16190efc1c7e94404b48f72af57/src/system/packages/brew/cask/artifacts.rs#L201-L237","documentation":"Cask artifact validation in parse_command_wrapper_artifact: a command_wrapper entry defined neither `content` nor `executable`, so there is nothing to wrap. This mirrors Homebrew cask stanza requirements and fires on an incomplete command_wrapper definition.","triggerScenarios":"A command_wrapper options object that is empty or only contains args/env, so both content and executable resolve to None.","commonSituations":"Authoring a cask with just a name and args, forgetting to specify what the wrapper runs; deleting the executable line when refactoring a cask definition.","solutions":["Add an `executable` option naming the binary to run.","Alternatively add a `content` option with inline script content.","Remove args/env if you intended content-only, since args/env require executable anyway."],"exampleFix":"// before\n[\"mytool\", {}]\n// after\n[\"mytool\", {\"executable\": \"mytool\"}]","handlingStrategy":"validation","validationCode":"fn cw_has_body(opts: &serde_json::Map<String, serde_json::Value>) -> bool {\n    opts.contains_key(\"content\") || opts.contains_key(\"executable\")\n}\nassert!(cw_has_body(&opts));","typeGuard":"fn has_content_or_executable(o: &serde_json::Value) -> bool {\n    o.get(\"content\").is_some() || o.get(\"executable\").is_some()\n}","tryCatchPattern":null,"preventionTips":["Always pair a command_wrapper name with content or executable","Template cask stanzas with the body pre-filled","Run schema validation on cask definitions before shipping"],"tags":["brew-cask","validation","missing-field","config"],"backgroundTag":"missing-required-config-field","analyzedSha":"afd2eddd3a50c16190efc1c7e94404b48f72af57","analyzedAt":"2026-09-09T01:38:25.179Z","contentChangedAt":"2026-09-09T01:38:25.179Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}