jdx/mise · error

{message}

Error message

{message}

What it means

string_array in src/system/hooks.rs validates that every element of a TOML array given to a hook's `run` is a string, bailing with a caller-supplied message (default: 'expected `run` to contain string commands'). It is raised while expanding a hook defined as an array when at least one element is a non-string TOML value. This keeps hook commands typed as strings so they can be trimmed, templated, and executed.

Solutions

  1. Quote every element in the run array so all are strings
  2. Remove non-string elements (numbers, booleans, nested tables) from the array
  3. If a command needs a number argument, embed it inside a quoted command string, e.g. run = ["sleep 2"]

Example fix

# before
run = ["echo ok", 2]
# after
run = ["echo ok", "sleep 2"]
Defensive patterns

Strategy: type-guard

Validate before calling

# before loading, ensure every element of run arrays is a string
bad = [x for x in run_list if not isinstance(x, str)]

Type guard

const isStringArray = (v) => Array.isArray(v) && v.every(x => typeof x === 'string');

Prevention

When it happens

Trigger: A hook `run` array containing a non-string element, e.g. run = ["echo ok", 42] or run = ["cmd", true], passed from from_toml into string_array.

Common situations: Accidentally mixing numeric exit codes or booleans into command arrays; programmatic TOML generation emitting unquoted values; copy-paste edits that leave a placeholder like 0 in the list.

Understand the failure class

Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.

Related errors


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

Appendix: source

Thrown at src/system/hooks.rs:125

                } else {
                    Some(Self {
                        phase,
                        run,
                        config_path: config_path.clone(),
                    })
                }
            })
            .collect();
        Ok(hooks)
    }
}

fn string_array(values: Vec<toml::Value>, message: &str) -> Result<Vec<String>> {
    let mut out = vec![];
    for value in values {
        match value {
            toml::Value::String(s) => out.push(s),
            _ => bail!("{message}"),
        }
    }
    Ok(out)
}

pub(crate) async fn run_phase(
    config: &Config,
    hooks: &[BootstrapHook],
    phase: BootstrapHookPhase,
    dry_run: bool,
) -> Result<()> {
    let phase_hooks: Vec<_> = hooks.iter().filter(|hook| hook.phase == phase).collect();
    if phase_hooks.is_empty() {
        return Ok(());
    }
    info!("bootstrap: {phase} hooks");
    let shell = Settings::get().default_inline_shell()?;
    let Some((program, shell_args)) = shell.split_first() else {

View on GitHub (pinned to 533346cc37)