jdx/mise · error

file changed during lockfile generation; retry the command

Error message

file {} changed during lockfile generation; retry the command

What it means

During `mise lock`, mise snapshots input files (configs, lockfiles) before generation and re-reads them afterwards. If any file's content differs from its snapshot, concurrent modification occurred while the lockfile was being computed, so results would be unreliable and the command aborts.

Solutions

  1. Re-run the same command — the error explicitly says retry
  2. Ensure no other mise processes are running concurrently (check `mise tasks`/CI parallelism)
  3. Disable auto-rewriting tools (editors, direnv hooks) that touch mise.toml while locking

Example fix

// before (concurrent runs in CI)
- run: mise lock &
- run: mise install &
// after
- run: mise lock
- run: mise install
Defensive patterns

Strategy: retry

Try / catch

// bash: retry on transient race
for i in 1 2 3; do mise lock && break || sleep 2; done

Prevention

When it happens

Trigger: Another mise process (or editor/tooling that rewrites config) modifies a config file or lockfile listed in the generation snapshots between the initial read and the verification in `verify_generation_snapshots`, called from `run_with_installed`.

Common situations: Running two `mise lock`/`mise install` commands concurrently in the same project; an IDE plugin or `direnv` rewriting `mise.toml` mid-command.

Related errors


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

Appendix: source

Thrown at src/cli/lock.rs:239

    if targets.len() < 2 {
        return true;
    }
    let mut canonical = BTreeSet::new();
    targets.all(|path| match fs::canonicalize(path) {
        Ok(path) => canonical.insert(path),
        // Missing files cannot take the fast path, so only existing targets
        // need to be distinct before one of them can be skipped.
        Err(error) if error.kind() == ErrorKind::NotFound => true,
        Err(_) => false,
    })
}

fn verify_generation_snapshots<'a>(
    snapshots: impl Iterator<Item = (&'a PathBuf, &'a Option<Vec<u8>>)>,
) -> Result<()> {
    for (path, content) in snapshots {
        if read_optional_file(path)? != *content {
            bail!(
                "file {} changed during lockfile generation; retry the command",
                display_path(path)
            );
        }
    }
    Ok(())
}

fn read_optional_file(path: &Path) -> Result<Option<Vec<u8>>> {
    match fs::read(path) {
        Ok(content) => Ok(Some(content)),
        Err(err) if err.kind() == ErrorKind::NotFound => Ok(None),
        Err(err) => Err(err.into()),
    }
}

fn prepare_lockfile_rollback(
    snapshots: &[LockfileSnapshot],

View on GitHub (pinned to 533346cc37)