jdx/mise · error
{} changed before application; nothing was written
Error message
{} changed before application; nothing was written What it means
Immediately before writing the planned batch, mise re-reads every live file and compares it (content and permissions) against the object captured when the plan was made. If any file changed between planning and application, the whole apply aborts with this error and nothing is written — an edit that arrived in the meantime is never overwritten by a stale plan.
Source
Thrown at src/system/history/sync/apply.rs:502
display_path(&step.path)
);
}
}
let candidate = heads
.candidate(repo, tree)?
.ok_or_else(|| eyre::eyre!("setup branch disappeared"))?;
super::files::audit_history(repo, &candidate.commit, &Default::default())?;
}
// Validate the complete batch again after acquiring the operation
// lock, before the first write.
for directory in &directories {
directory.validate()?;
}
for step in &ready {
if live_object(repo, &step.path)? != step.before
|| live_permissions(&step.path)? != step.before_mode
{
bail!(
"{} changed before application; nothing was written",
display_path(&step.path)
);
}
}
for directory in &mut directories {
directory.apply()?;
}
for step in &ready {
// the file may have changed since the plan was made: an edit
// that landed meanwhile is never overwritten (undo would bring
// back the planned version, not it)
if live_object(repo, &step.path)? != step.before
|| live_permissions(&step.path)? != step.before_mode
{
bail!(
"{} changed while the changes were being applied; nothing more was written. Run `mise bootstrap dotfiles pull` again",
display_path(&step.path)View on GitHub (pinned to afd2eddd3a)
Solutions
- Re-run `mise bootstrap dotfiles pull` to make a fresh plan that includes the concurrent change.
- Determine what modified the file (editor autosave, watcher, second mise process) and prevent concurrent writes during pull.
- If the concurrent edit should be kept, save it into the sync store first, then pull.
Example fix
// before: plan made, file changed afterwards
apply(plan).await?;
// after: guard pattern — detect and replan
if live_changed_since_plan(&step) {
plan = replan().await?;
}
apply(plan).await?; Defensive patterns
Strategy: retry
Validate before calling
# snapshot checksums before pulling and re-check after a failure md5sum ~/.zshrc > /tmp/before.md5 mise bootstrap dotfiles pull --dry-run
Try / catch
try {
await pull();
} catch (e) {
if (/changed before application/.test(e.message)) {
await sleep(250); // let concurrent writers settle
return await pull(); // replan including the concurrent change
}
throw e;
} Prevention
- Disable editor autosave for tracked dotfiles during pull.
- Ensure only one mise sync process runs at a time.
- Re-plan (re-run pull) after any known concurrent edit instead of forcing an old plan.
When it happens
Trigger: During apply, for a ready step: `live_object(repo, step.path) != step.before || live_permissions(&step.path) != step.before_mode` — the file (or its mode) on disk changed after the plan snapshot.
Common situations: Editor autosave fired between plan and apply; a chmod changed permissions; another sync/mise instance or a dotfile daemon touched the file concurrently; a slow, long-running apply on an actively edited machine.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- local files were saved after enrollment planning; retry pull
- {} changed while the changes were being applied; nothing mor
- {} changed during setup adoption; retry pull
- {} changed while preparing enrollment; concurrent declaratio
- {} changed in the complete repository merge; reconcile again
AI-assisted analysis of jdx/mise@afd2eddd3a (2026-09-09).
Data as JSON: /api/errors/ff49ffe0581520b7.
Report an issue: GitHub.