{"record":{"id":"33b6dd312ddba49b","repo":"jdx/mise","slug":"brew-cask-command-wrapper-requires-content-or-exe-33b6dd","errorCode":null,"errorMessage":"brew-cask: command_wrapper requires content or executable, not both","messagePattern":"brew-cask: command_wrapper requires content or executable, not both","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/system/packages/brew/cask/artifacts.rs","lineNumber":222,"sourceCode":"        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\n                        .as_str()\n                        .map(|value| (key.clone(), value.to_string()))\n                        .ok_or_else(|| {","sourceCodeStart":204,"sourceCodeEnd":240,"githubUrl":"https://github.com/jdx/mise/blob/afd2eddd3a50c16190efc1c7e94404b48f72af57/src/system/packages/brew/cask/artifacts.rs#L204-L240","documentation":"Thrown when a command_wrapper artifact specifies BOTH `content` and `executable`. These two options are mutually exclusive: the wrapper either writes inline content or invokes an executable, not both.","triggerScenarios":"A command_wrapper options object containing both a 'content' string and an 'executable' string at the same time.","commonSituations":"Merging two cask definitions or adding an executable wrapper to an existing content-based one without removing the old option.","solutions":["Remove the `content` option and keep `executable` (plus args/env).","Or remove `executable` (and its args/env) and keep `content` only."],"exampleFix":"// before\n[\"mytool\", {\"content\": \"#!/bin/sh\\necho hi\", \"executable\": \"mytool\"}]\n// after\n[\"mytool\", {\"content\": \"#!/bin/sh\\necho hi\"}]","handlingStrategy":"validation","validationCode":"fn cw_body_exclusive(o: &serde_json::Value) -> bool {\n    !(o.get(\"content\").is_some() && o.get(\"executable\").is_some())\n}\nassert!(cw_body_exclusive(&opts));","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Decide upfront: inline content OR executable, never both","When migrating wrappers, delete the replaced option","Add a unit test asserting mutual exclusivity of content/executable"],"tags":["brew-cask","validation","mutually-exclusive","config"],"backgroundTag":"mutually-exclusive-options","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"}