jdx/mise · error

brew-cask: : must be a boolean

Error message

brew-cask:{}: {kind} {field} must be a boolean

What it means

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.

Solutions

  1. Change the field to a real boolean: `must_succeed = true` (unquoted).
  2. Remove the field to accept its default value.
  3. If the value comes from templating, ensure interpolation emits a TOML bool, not a string.

Example fix

// before
[[flight.steps]]
type = "run"
command = "./install.sh"
must_succeed = "true"
// after
[[flight.steps]]
type = "run"
command = "./install.sh"
must_succeed = true
Defensive patterns

Strategy: validation

Validate before calling

const BOOL_FIELDS = ["must_succeed", "force", "dry_run"];
for (const f of BOOL_FIELDS)
  if (step[f] !== undefined && typeof step[f] !== "boolean")
    throw new Error(`${f} must be a boolean`);

Type guard

function isOptionalBool(v) {
  return v === undefined || typeof v === "boolean";
}

Try / catch

try {
  parseCaskArtifacts(cask);
} catch (err) {
  const m = err.message.match(/(\w+) must be a boolean/);
  if (m) {
    // convert step[m[1]] to a real boolean
  } else throw err;
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of jdx/mise@533346cc37 (2026-09-17). Data as JSON: /api/errors/5a51a9972dca254a. Report an issue: GitHub.

Appendix: source

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

                .iter()
                .map(|guard| parse_flight_guard(cask, kind, guard))
                .collect::<Result<Vec<_>>>()
        })
        .transpose()
        .map(|guards| guards.unwrap_or_default())
}

pub(super) fn parse_optional_flight_bool(
    cask: &Cask,
    kind: &str,
    object: &serde_json::Map<String, Value>,
    field: &str,
    default: bool,
) -> Result<bool> {
    match object.get(field) {
        None => Ok(default),
        Some(Value::Bool(value)) => Ok(*value),
        Some(_) => bail!("brew-cask:{}: {kind} {field} must be a boolean", cask.token),
    }
}

pub(super) fn parse_run_command(
    cask: &Cask,
    kind: &str,
    value: Option<&Value>,
) -> Result<FlightPath> {
    let object = value.and_then(Value::as_object).ok_or_else(|| {
        eyre!(
            "brew-cask:{}: unsupported {kind} run command metadata format",
            cask.token
        )
    })?;
    reject_unsupported_flight_fields(cask, kind, "run command", object, &["base", "path"])?;
    let path = object.get("path").and_then(Value::as_str).ok_or_else(|| {
        eyre!(
            "brew-cask:{}: unsupported {kind} run command path",

View on GitHub (pinned to 533346cc37)