{"record":{"id":"7bd17f69ba2acf9e","repo":"jdx/mise","slug":"interrupted-file-recovery-needs-attention-temporary-recovery","errorCode":null,"errorMessage":"interrupted file recovery needs attention; temporary recovery data was retained. {}. Run `mise dot recover` to retry, or inspect the files and use `recover <operation> --keep-current` to explicitly accept their current contents","messagePattern":"interrupted file recovery needs attention; temporary recovery data was retained\\. (.+?)\\. Run `mise dot recover` to retry, or inspect the files and use `recover <operation> --keep-current` to explicitly accept their current contents","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/system/history/recovery.rs","lineNumber":56,"sourceCode":"            continue;\n        }\n        let after = journal.iter().rev().find_map(|entry| match entry {\n            JournalEntry::Committed {\n                seq: recorded,\n                after,\n            } if *recorded as usize == seq => Some(after),\n            _ => None,\n        });\n        if unfinished_only && after.is_some() {\n            continue;\n        }\n        if let Err(error) = recover_path(state_dir, path, prior, after) {\n            blocked.push(path);\n            failures.push(format!(\"{}: {error:#}\", crate::file::display_path(path)));\n        }\n    }\n    if !failures.is_empty() {\n        bail!(\n            \"interrupted file recovery needs attention; temporary recovery data was retained. {}. Run `mise dot recover` to retry, or inspect the files and use `recover <operation> --keep-current` to explicitly accept their current contents\",\n            failures.join(\"; \")\n        );\n    }\n    Ok(())\n}\n\nfn recover_path(\n    state_dir: &Path,\n    path: &Path,\n    prior: &PathSnapshot,\n    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 {","sourceCodeStart":38,"sourceCodeEnd":74,"githubUrl":"https://github.com/jdx/mise/blob/533346cc374382b41ec5ff70536252b2e96e725c/src/system/history/recovery.rs#L38-L74","documentation":"recover_entries attempts to restore each path from an interrupted write operation. When any individual path recovery fails, it collects the per-path failures and bails, retaining the temporary recovery data so nothing is lost, and tells the user to run `mise dot recover` or accept current contents with `recover <operation> --keep-current`.","triggerScenarios":"recover_entries (via recover or recover_unfinished) iterates pending recovery entries and one or more recover_path calls return Err — e.g. the live file changed since the operation, the write completion was never recorded, a directory's contents could not be verified, or the snapshot validation failed.","commonSituations":"A mise process was killed mid dotfile write (power loss, Ctrl-C, OOM) leaving an unfinished recovery journal; on retry, the user or another tool edited the affected files so the recorded snapshots no longer match; the recovery store is partially corrupt.","solutions":["Run `mise dot recover` to retry recovery of the retained data.","For each listed failing path, compare the file against the intended content; if the current content is acceptable, run `mise dot recover <operation> --keep-current` to accept it explicitly.","Inspect the recovery/temp data referenced by the error for files that need manual copying back into place.","If files were changed intentionally, resolve path-by-path: restore expected content manually then re-run recover, or keep-current per operation."],"exampleFix":"// before: fails with retained temp data\n$ mise dot status   # shows unfinished recovery\n// after\n$ mise dot recover                       # retry\n$ mise dot recover <operation> --keep-current   # accept current contents","handlingStrategy":"try-catch","validationCode":"export function hasUnfinishedRecovery(statusOutput: string): boolean {\n  return /unfinished|pending recovery/i.test(statusOutput);\n}\n// run `mise dot status` before writes that could be interrupted","typeGuard":null,"tryCatchPattern":"try {\n  await dotRecover();\n} catch (e) {\n  if (/interrupted file recovery needs attention/.test(String(e))) {\n    // temp data retained; resolve per listed path\n    for (const p of listedPaths(String(e))) reviewOrKeepCurrent(p);\n    await dotRecover();\n  } else throw e;\n}","preventionTips":["Avoid killing mise during dotfile operations (use graceful termination)","Run `mise dot status` after crashes to detect unfinished recovery early","Keep other editors/sync tools from racing dotfile writes"],"tags":["recovery","dotfiles","interrupted-operation","filesystem"],"backgroundTag":"invalid-state-transition","analyzedSha":"533346cc374382b41ec5ff70536252b2e96e725c","analyzedAt":"2026-09-17T13:35:38.149Z","contentChangedAt":"2026-09-17T13:35:38.149Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}