jdx/mise · error
lockfile changed while generation was being prepared; retry…
Error message
lockfile {} changed while generation was being prepared; retry the command What it means
After acquiring transaction locks, `mise lock` re-verifies every input (configs, initial lockfiles, staged upgrade sources) against snapshots taken before lock acquisition. If a staged lockfile's content no longer matches its pre-lock snapshot, another writer changed it while mise waited for the lock, and generation would be based on stale data — so it aborts.
Solutions
- Re-run the command once no other mise writers are active — it is designed to be retried
- Serialize mise commands in CI (single job step, or a file lock around them)
- Identify the other writer (editor plugins, direnv, scripts calling `mise use`) and prevent concurrent writes
Example fix
// before mise lock --upgrade & mise install & wait // after mise lock --upgrade mise install
Defensive patterns
Strategy: retry
Try / catch
// bash: retry after concurrent-writer abort
mise lock --upgrade || { sleep 5; mise lock --upgrade; } Prevention
- Run only one lockfile-writing mise process per checkout
- Serialize mise steps in CI pipelines
- Avoid editing mise.lock manually while mise runs
When it happens
Trigger: A concurrent process rewrote a lockfile staged for upgrade between snapshotting and lock acquisition in `run_with_installed`; `read_optional_file(&staged.path)` differs from `staged.original_content`.
Common situations: Parallel `mise lock`/`mise install`/`mise use` invocations in monorepos or CI jobs sharing one checkout; a background tool rewriting mise.lock while you upgrade.
Related errors
- file changed during lockfile generation; retry the command
- 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/1a65c2d7c0d9acf0.
Report an issue: GitHub.
Appendix: source
Thrown at src/cli/lock.rs:937
})
.collect::<Result<Vec<_>>>()?;
let transaction_paths =
publication_lock_paths(&mutation_paths, &config_snapshots, &initial_lockfiles);
let mut transaction_locks = Vec::with_capacity(transaction_paths.len());
for path in transaction_paths.difference(&generation_lock_paths) {
transaction_locks.push(
crate::lock_file::LockFile::new(path)
.with_callback(|l| debug!("waiting for lock on {}", display_path(l)))
.lock()?,
);
}
// Lock acquisition may wait behind another writer. Recheck every input,
// including bumped configs and migration sources, under the transaction locks.
verify_generation_snapshots(config_snapshots.iter().chain(initial_lockfiles.iter()))?;
for staged in &staged_upgrade_writes {
if read_optional_file(&staged.path)? != staged.original_content {
bail!(
"lockfile {} changed while generation was being prepared; retry the command",
display_path(&staged.path)
);
}
}
verify_generation_snapshots(
snapshots
.iter()
.map(|snapshot| (&snapshot.path, &snapshot.content)),
)?;
// 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
// more file data to be written.
let rollbacks = prepare_lockfile_rollback(&snapshots)?;
let mut graph_cleanups = Vec::new();
verify_generation_snapshots(config_snapshots.iter().chain(initial_lockfiles.iter()))?;View on GitHub (pinned to 533346cc37)