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
- Re-run the same command — the error explicitly says retry
- Ensure no other mise processes are running concurrently (check `mise tasks`/CI parallelism)
- 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
- Do not run concurrent mise lock/install commands in one project
- Disable editors/plugins that auto-rewrite mise.toml during CI
- Serialize mise operations in scripts
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
- lockfile changed while generation was being prepared; retry…
- changed while the changes were being applied; nothing more…
- lockfile symlink changed during preparation; retry the…
- brew-cask: : Homebrew took ownership of this cask while…
- changed after permission planning; retry pull
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)