{"record":{"id":"50555f330459bf9d","repo":"jdx/mise","slug":"changed-after-the-operation-left-untouched","errorCode":null,"errorMessage":"changed after the operation; left untouched","messagePattern":"changed after the operation; left untouched","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/system/history/recovery.rs","lineNumber":86,"sourceCode":"    after: Option<&PathState>,\n) -> Result<()> {\n    validate_destination(path)?;\n    let comparison = tempfile::tempdir()?;\n    let depth = if matches!(prior, PathSnapshot::Directory { .. }) {\n        Capture::Shallow\n    } else {\n        Capture::Full\n    };\n    // Comparing must not leave copies of concurrent user edits in the store.\n    let current = PathSnapshot::capture_with(comparison.path(), path, depth);\n    if !matches!(prior, PathSnapshot::Unrecorded { .. }) && &current == prior {\n        return Ok(());\n    }\n    let Some(after) = after else {\n        bail!(\"write completion was not recorded; inspect the live file before retrying recovery\");\n    };\n    if PathState::observe(path) != *after {\n        bail!(\"changed after the operation; left untouched\");\n    }\n    // Entry count alone cannot establish a directory's identity. Never\n    // replace a populated directory on that evidence.\n    if matches!(after, PathState::Dir { entries, .. } if *entries != 0)\n        && !(matches!(prior, PathSnapshot::Directory { .. })\n            && matches!(\n                after,\n                PathState::Dir {\n                    identity: Some(_),\n                    ..\n                }\n            ))\n    {\n        bail!(\"directory contents cannot be verified safely; left untouched\");\n    }\n    validate_snapshot(state_dir, prior)?;\n    if PathState::observe(path) != *after {\n        bail!(\"changed while preparing recovery; left untouched\");","sourceCodeStart":68,"sourceCodeEnd":104,"githubUrl":"https://github.com/jdx/mise/blob/afd2eddd3a50c16190efc1c7e94404b48f72af57/src/system/history/recovery.rs#L68-L104","documentation":"recover_path compares PathState::observe(path) against the recorded 'after' state before restoring; if they differ, the file was modified after the operation completed and recovery refuses to overwrite those newer edits, leaving the file untouched.","triggerScenarios":"recover_path invoked when the live path's observed state (contents/mode) no longer equals the 'after' snapshot captured at operation completion — i.e. something edited the file between the operation and recovery.","commonSituations":"The user (or an editor/sync tool like Dropbox) changed the dotfile after the failed operation but before running recover; concurrent shells writing the same rc file; recovery run long after the interruption.","solutions":["Decide which version to keep: if the current edits are wanted, use `recover <operation> --keep-current`.","If the recorded 'after' content is wanted, revert the live file to it manually, then re-run recovery.","Stop editors/sync tools touching the file, then immediately retry `mise bootstrap dotfiles recover`.","Diff the live file against the retained recovery data to choose the correct content."],"exampleFix":"// before: file was edited after the operation, recover refuses\n$ mise bootstrap dotfiles recover\n// after: explicitly accept the newer edits\n$ mise bootstrap dotfiles recover <operation> --keep-current","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"match recover_entries(state_dir, plan) {\n    Err(e) if e.to_string().contains(\"changed after the operation\") => {\n        eprintln!(\"live file was edited; diff it, then choose --keep-current or restore\");\n    }\n    other => other?,\n}","preventionTips":["Don't edit dotfiles between an interrupted operation and its recovery.","Disable file-sync tools (Dropbox/iCloud) for dotfile paths during recovery.","Run recovery promptly after the interruption."],"tags":["recovery","concurrency","dotfiles","conflict"],"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"}