jdx/mise · error

invalid lockfile format for tool {short}: expected array ([[

Error message

invalid lockfile format for tool {short}: expected array ([[tools.{short}]])

What it means

In mise.lock, each tools.<short> value must be an array of tables — one [[tools.<short>]] entry per locked version (src/lockfile.rs:883-894). A non-array value (inline table, bare string) bails, naming the tool.

Source

Thrown at src/lockfile.rs:892

        let mut table: toml::Table = toml::from_str(&content)?;

        let tools: toml::Table = table
            .remove("tools")
            .unwrap_or(toml::Table::new().into())
            .try_into()?;

        let mut lockfile = Lockfile {
            generated_header_url,
            ..Default::default()
        };

        for (short, value) in tools {
            let versions = match value {
                toml::Value::Array(arr) => arr
                    .into_iter()
                    .map(LockfileTool::try_from)
                    .collect::<Result<Vec<_>>>()?,
                _ => bail!(
                    "invalid lockfile format for tool {short}: expected array ([[tools.{short}]])"
                ),
            };
            lockfile.tools.insert(short, versions);
        }

        // Parse conda-packages section: platform -> basename -> CondaPackageInfo
        if let Some(conda_packages) = table.remove("conda-packages") {
            let platforms: toml::Table = conda_packages.try_into()?;
            for (platform, packages) in platforms {
                let packages_table: toml::Table = packages.try_into()?;
                for (basename, info) in packages_table {
                    let info: CondaPackageInfo = info.try_into()?;
                    lockfile
                        .conda_packages
                        .entry(platform.clone())
                        .or_default()
                        .insert(basename, info);

View on GitHub (pinned to 6f52dcdf99)

Solutions

  1. Regenerate the lockfile: rm mise.lock && mise lock.
  2. Upgrade mise so writer and reader agree on the [[tools.<name>]] shape.
  3. Resolve lockfile merge conflicts by regenerating, not by hand-merging.

Example fix

# before (mise.lock, wrong shape)
[tools]
node = "22.0.0"

# after — regenerate; correct shape is one [[tools.node]] table per version
$ rm mise.lock && mise lock
Defensive patterns

Strategy: validation

Validate before calling

# CI guard: tools.<short> must be an array (of tables)
python3 -c "
import tomllib
for name, v in tomllib.load(open('mise.lock', 'rb')).get('tools', {}).items():
    if not isinstance(v, list):
        raise SystemExit('tools.%s must be an array of tables' % name)
"

Try / catch

On "invalid lockfile format for tool …", regenerate the lockfile rather than reshaping it by hand; if the shape came from another mise version, upgrade/downgrade to match before re-locking, then fail the job with that guidance if lockfiles are protected.

Prevention

When it happens

Trigger: tools.node = "22" or tools.python = { version = "3.12" } in mise.lock — hand-edited files, output from a much older/experimental mise format, or structural drift between versions.

Common situations: Hand-editing mise.lock instead of using mise lock; lockfiles produced by pre-release formats; merge conflicts resolved incorrectly.

Related errors


AI-assisted analysis of jdx/mise@6f52dcdf99 (2026-08-22). Data as JSON: /api/errors/5b8935eb6d66c964. Report an issue: GitHub.