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
- Change the hook value to a plain string, e.g. run = "echo hi"
- Use an array of strings for multiple commands, e.g. run = ["cmd1", "cmd2"]
- If using a table form, ensure it has a `run` key whose value is a string or string array
- 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
- Always define hooks as strings or arrays of strings
- Use a TOML schema validator/JSON schema for config files in CI
- Never put bare numbers or booleans in command lists
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
- command wrapper for must have a non-blank command
- [daemons. ] requires preset when specifying version or…
- [daemons. ] requires run or preset
- agent ' ' `start_calendar_interval. ` must be between and
- agent ' ' `start_calendar_interval` must set at least one…
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)