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

  1. Re-run `mise bootstrap dotfiles pull` to make a fresh plan that includes the concurrent change.
  2. Determine what modified the file (editor autosave, watcher, second mise process) and prevent concurrent writes during pull.
  3. 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

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


AI-assisted analysis of jdx/mise@afd2eddd3a (2026-09-09). Data as JSON: /api/errors/ff49ffe0581520b7. Report an issue: GitHub.