jdx/mise · error

expected a string, array of strings, or table with `run`

Error message

expected a string, array of strings, or table with `run`

What it means

This error comes from Hook::from_toml in src/system/hooks.rs when parsing a hook's `run` field from a TOML config. Hooks accept either a plain string, an array of strings (multiple commands), or a table containing a `run` key; any other TOML type (integer, boolean, nested table without `run`, etc.) is rejected with this message. It is a configuration schema-validation guard so malformed hook definitions fail at parse time instead of at hook execution.

Solutions

  1. Change the hook value to a plain string, e.g. run = "echo hi"
  2. Use an array of strings for multiple commands, e.g. run = ["cmd1", "cmd2"]
  3. If using a table form, ensure it has a `run` key whose value is a string or string array
  4. Validate the TOML file syntax and types with a TOML linter before loading

Example fix

# before
[settings.hooks.postinstall]
run = 42
# after
[settings.hooks.postinstall]
run = "echo postinstall"
Defensive patterns

Strategy: validation

Validate before calling

# pre-check a hook value before writing/committing TOML
import toml
v = cfg["settings"]["hooks"]["postinstall"]["run"]
assert isinstance(v, str) or (isinstance(v, list) and all(isinstance(x, str) for x in v)), "run must be string or string[]"

Type guard

function isHookRun(v) { return typeof v === 'string' || (Array.isArray(v) && v.every(x => typeof x === 'string')); }

Prevention

When it happens

Trigger: Setting `run` (or a hook entry) to a TOML type other than string/array-of-strings/table-with-`run`: e.g. run = 42, run = true, run = { cmd = "..." }, or a deeply nested table lacking a `run` key.

Common situations: Typos in mise.toml/config.toml hook definitions; hand-editing hooks and accidentally quoting or unquoting values; YAML-to-TOML conversion tools emitting non-string scalars; forgetting the `run` key inside a hook table.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


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

Appendix: source

Thrown at src/system/hooks.rs:98

                .map(|phase| phase.as_str())
                .collect::<Vec<_>>();
            bail!(
                "unknown bootstrap hook phase {phase_raw:?}; valid phases are: {}",
                valid.join(", ")
            );
        };
        let runs = match value {
            toml::Value::String(run) => vec![run],
            toml::Value::Array(values) => string_array(values, "expected string commands")?,
            toml::Value::Table(mut table) => match table.remove("run") {
                Some(toml::Value::String(run)) => vec![run],
                Some(toml::Value::Array(values)) => {
                    string_array(values, "expected `run` to contain string commands")?
                }
                Some(_) => bail!("expected `run` to be a string or array of strings"),
                None => bail!("expected a `run` command"),
            },
            _ => bail!("expected a string, array of strings, or table with `run`"),
        };
        let hooks = runs
            .into_iter()
            .filter_map(|run| {
                let run = run.trim().to_string();
                if run.is_empty() {
                    warn!("[bootstrap.hooks.{phase}]: empty command, ignoring entry");
                    None
                } else {
                    Some(Self {
                        phase,
                        run,
                        config_path: config_path.clone(),
                    })
                }
            })
            .collect();
        Ok(hooks)

View on GitHub (pinned to 533346cc37)