{"record":{"id":"ff49ffe0581520b7","repo":"jdx/mise","slug":"changed-before-application-nothing-was-written","errorCode":null,"errorMessage":"{} changed before application; nothing was written","messagePattern":"(.+?) changed before application; nothing was written","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/system/history/sync/apply.rs","lineNumber":502,"sourceCode":"                        display_path(&step.path)\n                    );\n                }\n            }\n            let candidate = heads\n                .candidate(repo, tree)?\n                .ok_or_else(|| eyre::eyre!(\"setup branch disappeared\"))?;\n            super::files::audit_history(repo, &candidate.commit, &Default::default())?;\n        }\n        // Validate the complete batch again after acquiring the operation\n        // lock, before the first write.\n        for directory in &directories {\n            directory.validate()?;\n        }\n        for step in &ready {\n            if live_object(repo, &step.path)? != step.before\n                || live_permissions(&step.path)? != step.before_mode\n            {\n                bail!(\n                    \"{} changed before application; nothing was written\",\n                    display_path(&step.path)\n                );\n            }\n        }\n        for directory in &mut directories {\n            directory.apply()?;\n        }\n        for step in &ready {\n            // the file may have changed since the plan was made: an edit\n            // that landed meanwhile is never overwritten (undo would bring\n            // back the planned version, not it)\n            if live_object(repo, &step.path)? != step.before\n                || live_permissions(&step.path)? != step.before_mode\n            {\n                bail!(\n                    \"{} changed while the changes were being applied; nothing more was written. Run `mise bootstrap dotfiles pull` again\",\n                    display_path(&step.path)","sourceCodeStart":484,"sourceCodeEnd":520,"githubUrl":"https://github.com/jdx/mise/blob/afd2eddd3a50c16190efc1c7e94404b48f72af57/src/system/history/sync/apply.rs#L484-L520","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before: plan made, file changed afterwards\napply(plan).await?;\n// after: guard pattern — detect and replan\nif live_changed_since_plan(&step) {\n    plan = replan().await?;\n}\napply(plan).await?;","handlingStrategy":"retry","validationCode":"# snapshot checksums before pulling and re-check after a failure\nmd5sum ~/.zshrc > /tmp/before.md5\nmise bootstrap dotfiles pull --dry-run","typeGuard":null,"tryCatchPattern":"try {\n  await pull();\n} catch (e) {\n  if (/changed before application/.test(e.message)) {\n    await sleep(250); // let concurrent writers settle\n    return await pull(); // replan including the concurrent change\n  }\n  throw e;\n}","preventionTips":["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."],"tags":["sync","concurrency","race-condition","retry","dotfiles"],"backgroundTag":"invalid-state-transition","analyzedSha":"afd2eddd3a50c16190efc1c7e94404b48f72af57","analyzedAt":"2026-09-09T01:38:25.179Z","contentChangedAt":"2026-09-09T01:38:25.179Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}