{"record":{"id":"1a65c2d7c0d9acf0","repo":"jdx/mise","slug":"lockfile-changed-while-generation-was-being-prepared-retry","errorCode":null,"errorMessage":"lockfile {} changed while generation was being prepared; retry the command","messagePattern":"lockfile (.+?) changed while generation was being prepared; retry the command","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/cli/lock.rs","lineNumber":937,"sourceCode":"                })\n                .collect::<Result<Vec<_>>>()?;\n            let transaction_paths =\n                publication_lock_paths(&mutation_paths, &config_snapshots, &initial_lockfiles);\n            let mut transaction_locks = Vec::with_capacity(transaction_paths.len());\n            for path in transaction_paths.difference(&generation_lock_paths) {\n                transaction_locks.push(\n                    crate::lock_file::LockFile::new(path)\n                        .with_callback(|l| debug!(\"waiting for lock on {}\", display_path(l)))\n                        .lock()?,\n                );\n            }\n\n            // Lock acquisition may wait behind another writer. Recheck every input,\n            // including bumped configs and migration sources, under the transaction locks.\n            verify_generation_snapshots(config_snapshots.iter().chain(initial_lockfiles.iter()))?;\n            for staged in &staged_upgrade_writes {\n                if read_optional_file(&staged.path)? != staged.original_content {\n                    bail!(\n                        \"lockfile {} changed while generation was being prepared; retry the command\",\n                        display_path(&staged.path)\n                    );\n                }\n            }\n\n            verify_generation_snapshots(\n                snapshots\n                    .iter()\n                    .map(|snapshot| (&snapshot.path, &snapshot.content)),\n            )?;\n            // Materialize and sync every rollback replacement before the first\n            // mutation. Recovery then only needs same-directory renames, so a\n            // later disk-full failure cannot prevent restoration by requiring\n            // more file data to be written.\n            let rollbacks = prepare_lockfile_rollback(&snapshots)?;\n            let mut graph_cleanups = Vec::new();\n            verify_generation_snapshots(config_snapshots.iter().chain(initial_lockfiles.iter()))?;","sourceCodeStart":919,"sourceCodeEnd":955,"githubUrl":"https://github.com/jdx/mise/blob/533346cc374382b41ec5ff70536252b2e96e725c/src/cli/lock.rs#L919-L955","documentation":"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.","triggerScenarios":"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`.","commonSituations":"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.","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"],"exampleFix":"// before\nmise lock --upgrade &\nmise install &\nwait\n// after\nmise lock --upgrade\nmise install","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"// bash: retry after concurrent-writer abort\nmise lock --upgrade || { sleep 5; mise lock --upgrade; }","preventionTips":["Run only one lockfile-writing mise process per checkout","Serialize mise steps in CI pipelines","Avoid editing mise.lock manually while mise runs"],"tags":["lockfile","concurrency","race-condition","retry"],"backgroundTag":"file-changed-during-operation","analyzedSha":"533346cc374382b41ec5ff70536252b2e96e725c","analyzedAt":"2026-09-17T13:35:38.149Z","contentChangedAt":"2026-09-17T13:35:38.149Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}