{"record":{"id":"5a51a9972dca254a","repo":"jdx/mise","slug":"brew-cask-kind-field-must-be-a-boolean","errorCode":null,"errorMessage":"brew-cask:{}: {kind} {field} must be a boolean","messagePattern":"brew-cask:(.+?): (.+?) (.+?) must be a boolean","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/system/packages/brew/cask/artifacts.rs","lineNumber":927,"sourceCode":"                .iter()\n                .map(|guard| parse_flight_guard(cask, kind, guard))\n                .collect::<Result<Vec<_>>>()\n        })\n        .transpose()\n        .map(|guards| guards.unwrap_or_default())\n}\n\npub(super) fn parse_optional_flight_bool(\n    cask: &Cask,\n    kind: &str,\n    object: &serde_json::Map<String, Value>,\n    field: &str,\n    default: bool,\n) -> Result<bool> {\n    match object.get(field) {\n        None => Ok(default),\n        Some(Value::Bool(value)) => Ok(*value),\n        Some(_) => bail!(\"brew-cask:{}: {kind} {field} must be a boolean\", cask.token),\n    }\n}\n\npub(super) fn parse_run_command(\n    cask: &Cask,\n    kind: &str,\n    value: Option<&Value>,\n) -> Result<FlightPath> {\n    let object = value.and_then(Value::as_object).ok_or_else(|| {\n        eyre!(\n            \"brew-cask:{}: unsupported {kind} run command metadata format\",\n            cask.token\n        )\n    })?;\n    reject_unsupported_flight_fields(cask, kind, \"run command\", object, &[\"base\", \"path\"])?;\n    let path = object.get(\"path\").and_then(Value::as_str).ok_or_else(|| {\n        eyre!(\n            \"brew-cask:{}: unsupported {kind} run command path\",","sourceCodeStart":909,"sourceCodeEnd":945,"githubUrl":"https://github.com/jdx/mise/blob/533346cc374382b41ec5ff70536252b2e96e725c/src/system/packages/brew/cask/artifacts.rs#L909-L945","documentation":"Boolean flight-step fields (such as `must_succeed`, `force`, `dry_run`, etc.) parsed via `parse_optional_flight_bool` must be actual booleans when present. A non-boolean value of any kind is rejected, with the cask token, step kind, and offending field name interpolated into the message.","triggerScenarios":"A flight step (copy/symlink/run/terminate_process) has a boolean-typed field set to a non-bool, e.g. `must_succeed = \"true\"`, `dry_run = 1`, or a nested table where a bool was expected.","commonSituations":"TOML strings left unquoted-vs-quoted confusion (`\"true\"` is a string, not a bool), using 0/1 from other config languages, or nested-table indentation errors on the field.","solutions":["Change the field to a real boolean: `must_succeed = true` (unquoted).","Remove the field to accept its default value.","If the value comes from templating, ensure interpolation emits a TOML bool, not a string."],"exampleFix":"// before\n[[flight.steps]]\ntype = \"run\"\ncommand = \"./install.sh\"\nmust_succeed = \"true\"\n// after\n[[flight.steps]]\ntype = \"run\"\ncommand = \"./install.sh\"\nmust_succeed = true","handlingStrategy":"validation","validationCode":"const BOOL_FIELDS = [\"must_succeed\", \"force\", \"dry_run\"];\nfor (const f of BOOL_FIELDS)\n  if (step[f] !== undefined && typeof step[f] !== \"boolean\")\n    throw new Error(`${f} must be a boolean`);","typeGuard":"function isOptionalBool(v) {\n  return v === undefined || typeof v === \"boolean\";\n}","tryCatchPattern":"try {\n  parseCaskArtifacts(cask);\n} catch (err) {\n  const m = err.message.match(/(\\w+) must be a boolean/);\n  if (m) {\n    // convert step[m[1]] to a real boolean\n  } else throw err;\n}","preventionTips":["Write TOML booleans unquoted: `true`/`false`, never \"true\"/\"false\" or 1/0.","Lint cask TOML for stringified booleans on boolean fields.","When templating, coerce interpolated values to booleans before emitting."],"tags":["brew-cask","config","type-mismatch","boolean"],"backgroundTag":"config-type-mismatch","analyzedSha":"533346cc374382b41ec5ff70536252b2e96e725c","analyzedAt":"2026-09-17T13:35:38.149Z","contentChangedAt":"2026-09-17T13:35:38.149Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}