jdx/mise · error

lockfile {} changed while the format upgrade was being prepa

Error message

lockfile {} changed while the format upgrade was being prepared; retry `mise lock --upgrade`

What it means

To upgrade the lockfile format safely, mise stages writes for all affected lockfiles and, just before committing them, re-reads each file to confirm it still matches the content captured when the upgrade was prepared. If any file changed in between, this error is thrown to avoid clobbering concurrent modifications; the user is told to retry.

Source

Thrown at src/cli/lock.rs:674

                .map(|staged| staged.path.clone())
                .chain(
                    migration_paths
                        .iter()
                        .flat_map(|(source, target)| [source.clone(), target.clone()]),
                )
                .collect();
            let mut transaction_locks = Vec::with_capacity(transaction_paths.len());
            for path in &transaction_paths {
                transaction_locks.push(
                    crate::lock_file::LockFile::new(path)
                        .with_callback(|l| debug!("waiting for lock on {}", display_path(l)))
                        .lock()?,
                );
            }

            for staged in &staged_upgrade_writes {
                if read_optional_file(&staged.path)? != staged.original_content {
                    bail!(
                        "lockfile {} changed while the format upgrade was being prepared; retry `mise lock --upgrade`",
                        display_path(&staged.path)
                    );
                }
            }

            let snapshots = transaction_paths
                .iter()
                .map(|path| {
                    Ok(LockfileSnapshot {
                        path: path.clone(),
                        content: read_optional_file(path)?,
                    })
                })
                .collect::<Result<Vec<_>>>()?;
            // Materialize and sync every rollback replacement before the first
            // mutation. Recovery then only needs same-directory renames, so a
            // later disk-full failure cannot prevent restoration by requiring

View on GitHub (pinned to afd2eddd3a)

Solutions

  1. Simply retry `mise lock --upgrade` once no other mise/editor process is running — the message says exactly this.
  2. Close IDE plugins or background tasks that rewrite mise config files while the upgrade runs.
  3. If a specific lockfile keeps changing, commit or stash local changes first so nothing rewrites it.
  4. Run the upgrade on a clean working tree to eliminate concurrent writers.
Defensive patterns

Strategy: retry

Validate before calling

git status --porcelain -- '**/mise.lock'  # check no concurrent writers before upgrading

Try / catch

# shell
for i in 1 2 3; do
  mise lock --upgrade && break
  sleep 2
done

Prevention

When it happens

Trigger: Run `mise lock --upgrade` in a directory tree where another process (editor, `mise install`, another mise instance, git checkout) modifies one of the staged lockfiles between the prepare phase and the final write, so `read_optional_file(&staged.path)` no longer equals `staged.original_content`.

Common situations: Running `mise lock --upgrade` while an IDE with mise integration auto-writes mise.toml/lockfiles; two terminals running mise commands simultaneously; a background `git pull`/`git checkout` touching the lockfile mid-upgrade.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


AI-assisted analysis of jdx/mise@afd2eddd3a (2026-09-09). Data as JSON: /api/errors/320b3fc7c6009db7. Report an issue: GitHub.