jdx/mise · error
{} changed while preparing enrollment; concurrent declaratio
Error message
{} changed while preparing enrollment; concurrent declaration edit preserved; retry What it means
While enrolling a dotfile, mise verifies the declaration file's contents still match what was read earlier (`expected`). If the on-disk content changed between read and commit — a concurrent edit — track aborts instead of overwriting someone else's change, telling the user to retry.
Source
Thrown at src/cli/dotfiles/track.rs:316
declaration_lock_for(&crate::config::global_shared_config_path())
}
fn declaration_lock_for(config: &Path) -> Result<fslock::LockFile> {
crate::lock_file::LockFile::new(&config.with_extension("dotfiles-declarations.lock"))
.try_lock()?
.ok_or_else(|| {
eyre::eyre!("another tracking declaration command is running; retry shortly")
})
}
fn check_declaration(path: &Path, expected: Option<&str>) -> Result<()> {
let current = match std::fs::read_to_string(path) {
Ok(body) => Some(body),
Err(error) if error.kind() == std::io::ErrorKind::NotFound => None,
Err(error) => return Err(error.into()),
};
if current.as_deref() != expected {
bail!(
"{} changed while preparing enrollment; concurrent declaration edit preserved; retry",
display_path(path)
);
}
Ok(())
}
fn commit_declaration(
path: &Path,
expected: Option<&str>,
prepared: file::PreparedAtomicWrite,
) -> Result<()> {
// Check after formatting, directory creation, writing, and fsync. The
// declaration lock coordinates mise writers; unrelated editors do not
// participate, so this is not a filesystem compare-and-swap guarantee.
check_declaration(path, expected)?;
prepared.commit()
}View on GitHub (pinned to afd2eddd3a)
Solutions
- Retry `mise bootstrap dotfiles track <target>` once the other edit settles
- Ensure no editor or process is writing the declaration file concurrently
- Commit declaration edits through one tool at a time
Defensive patterns
Strategy: retry
Validate before calling
# ensure no writer holds the declaration file before tracking flock -n /path/to/declarations.lock -c 'mise bootstrap dotfiles track ~/target' || echo 'declaration busy'
Try / catch
until mise bootstrap dotfiles track ~/target 2>&1; do case "$?" in 0) break;; esac grep -q 'concurrent declaration edit' log && sleep 1 || break done
Prevention
- Close editors holding the declaration file open with autosave
- Run one dotfiles track/config-edit process at a time
- Pause file-sync tools (Dropbox/syncthing) during bulk enrollment
When it happens
Trigger: `dotfiles track` preparing enrollment of a declaration (e.g. declarations file in mise config) while another process/editor modifies that file between the initial read and the `check_declaration` compare-then-commit.
Common situations: Two terminals running `dotfiles track`/config edits simultaneously; an editor auto-saving the declaration file mid-command; sync tools (dropbox/git hooks) touching the file during enrollment.
Related errors
- {} changed before application; nothing was written
- target changed after unapply planning
- changed after the operation; left untouched
- changed while preparing recovery; left untouched
- local files were saved after enrollment planning; retry pull
AI-assisted analysis of jdx/mise@afd2eddd3a (2026-09-09).
Data as JSON: /api/errors/49f09f393e46b82b.
Report an issue: GitHub.