{"record":{"id":"1d0f7cf6cd7d9a05","repo":"jdx/mise","slug":"brew-cask-unresolved-recovery-for-still-preser","errorCode":null,"errorMessage":"brew-cask: unresolved recovery for {} still preserves its original at {}","messagePattern":"brew-cask: unresolved recovery for (.+?) still preserves its original at (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/system/packages/brew/cask.rs","lineNumber":3174,"sourceCode":"        return Ok(());\n    };\n    for entry in entries.flatten() {\n        let path = entry.path();\n        if path\n            .extension()\n            .is_none_or(|extension| extension != \"recovery\")\n        {\n            continue;\n        }\n        let Ok(body) = file::read_to_string(&path) else {\n            continue;\n        };\n        let Ok(record) = serde_json::from_str::<FlightRecoveryRecord>(&body) else {\n            continue;\n        };\n        if record.target == target {\n            if let Some(backup) = record.backup {\n                bail!(\n                    \"brew-cask: unresolved recovery for {} still preserves its original at {}\",\n                    target.display(),\n                    backup.display()\n                );\n            }\n            bail!(\n                \"brew-cask: unresolved recovery for newly created target {}\",\n                target.display()\n            );\n        }\n    }\n    Ok(())\n}\n\nfn recover_flight_backups() -> Result<()> {\n    let root = flight_recovery_root();\n    recover_flight_backups_in(&root)\n}","sourceCodeStart":3156,"sourceCodeEnd":3192,"githubUrl":"https://github.com/jdx/mise/blob/9dcfcaa0dc8747a2577d3270b69bb9d8313b2807/src/system/packages/brew/cask.rs#L3156-L3192","documentation":"When mise moves an existing file aside during artifact installation it writes a flight-recovery record (*.recovery JSON under the state dir) that is removed when the transaction commits. ensure_no_unresolved_flight_recovery scans these records before operating on a target; finding one that still points at a preserved backup means an earlier run was interrupted mid-transaction, so mise refuses rather than risk losing the original.","triggerScenarios":"A previous cask install/upgrade was killed (Ctrl-C, crash, reboot) between moving the original aside and committing; the recovery pass after that crash itself failed or never ran.","commonSituations":"Interrupted upgrades; power loss mid-install; users killing the process when it appeared stuck.","solutions":["Re-run the same cask command: recovery of pending flights runs first and normally completes it","If the target state is known-good, restore manually: move the backup file (path in the message) back over the target, then delete the matching *.recovery record under the flight-recovery root in mise's state dir","If recovery cannot complete, report it with the record contents"],"exampleFix":"# manual cleanup after confirming the target is fine\nmv '/path/in/error/backup' '/path/in/error/target'\nrm \"${XDG_STATE_HOME:-~/.local/state}/mise/brew-cask/flight-recovery/example.recovery\"","handlingStrategy":"retry","validationCode":"// Before installing over a target, run pending-flight recovery first\nlet root = flight_recovery_root();\nfor entry in std::fs::read_dir(&root).ok().into_iter().flatten().flatten() {\n    let path = entry.path();\n    if path.extension().is_some_and(|e| e == \"recovery\") {\n        recover_flight_backups()?; // complete pending flights before proceeding\n        break;\n    }\n}","typeGuard":null,"tryCatchPattern":"match install_cask(&cask) {\n    Err(e) if e.to_string().contains(\"unresolved recovery\") => {\n        // a previous run was interrupted: complete recovery, then retry once\n        recover_flight_backups()?;\n        install_cask(&cask)?\n    }\n    other => other?,\n}","preventionTips":["Let cask installs/upgrades finish instead of killing them mid-flight","After a crash, re-run the same command so recovery completes before new work","Do not delete the flight-recovery state dir manually while records exist"],"tags":["brew-cask","recovery","interrupted-install","transaction"],"backgroundTag":"interrupted-operation-recovery","analyzedSha":"9dcfcaa0dc8747a2577d3270b69bb9d8313b2807","analyzedAt":"2026-08-17T14:28:50.624Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}