{"record":{"id":"0e1ee2c46f8fb170","repo":"jdx/mise","slug":"brew-cask-unresolved-recovery-for-newly-created-t","errorCode":null,"errorMessage":"brew-cask: unresolved recovery for newly created target {}","messagePattern":"brew-cask: unresolved recovery for newly created target (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/system/packages/brew/cask.rs","lineNumber":3306,"sourceCode":"            .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}\n\nfn recover_flight_backups_in(root: &Path) -> Result<()> {\n    let Ok(entries) = std::fs::read_dir(root) else {\n        return Ok(());\n    };\n    for entry in entries {","sourceCodeStart":3288,"sourceCodeEnd":3324,"githubUrl":"https://github.com/jdx/mise/blob/6f52dcdf99e282ef7a7db68c81301fa4618d0f79/src/system/packages/brew/cask.rs#L3288-L3324","documentation":"Same pre-flight scan (ensure_no_unresolved_flight_recovery), but the matching FlightRecoveryRecord has no backup — it was written when the transaction created a brand-new target that must be removed if the operation doesn't commit. An outstanding record means a previous run created this path and died before finishing, so mise refuses to operate on it again until that state is resolved.","triggerScenarios":"An interrupted operation that had just created the target file/directory (no prior original existed, hence no backup); the corresponding absent-*.recovery record for it still exists in the flight-recovery directory.","commonSituations":"Crashed or killed installs leaving newly created files behind; partially written targets blocking every retry of the same cask.","solutions":["Re-run the same mise brew command so built-in recovery finishes removing the created target","Or remove the newly created target manually plus its *.recovery record, then retry","Open the record JSON and use its target field to identify exactly which path is pending","Let mise roll back rather than killing it mid-cask-operation"],"exampleFix":"# before: stale absent-record\n$ mise brew install --cask foo   # refuses: newly created target pending\n\n# after\n$ rm \"<target-path-from-error>\"\n$ rm \"<state>/brew-cask/flight-recovery/absent-<hash>.recovery\"\n$ mise brew install --cask foo","handlingStrategy":"validation","validationCode":"// Detect pending 'absent' recovery records for a target before install.\nfn pending_absent_recovery(target: &Path) -> Option<PathBuf> {\n    let dir = state_dir().join(\"brew-cask/flight-recovery\");\n    std::fs::read_dir(dir).ok()?.flatten().map(|e| e.path())\n        .filter(|p| p.extension().is_some_and(|e| e == \"recovery\"))\n        .find(|p| std::fs::read_to_string(p).ok()\n            .and_then(|b| serde_json::from_str::<FlightRecoveryRecord>(&b).ok())\n            .is_some_and(|r| r.target == target && r.backup.is_none()))\n}","typeGuard":null,"tryCatchPattern":"if let Err(e) = install_cask(&cask) {\n    if e.to_string().contains(\"unresolved recovery for newly created target\") {\n        // remove the created target + its absent-*.recovery record, then retry\n    }\n}","preventionTips":["Re-run the interrupted command first — recovery runs automatically","Read the record's target field to find the exact pending path","Remove both the pending target and the record together, never just one"],"tags":["brew-cask","recovery","interrupted-install","transaction","state"],"backgroundTag":"leftover-recovery-state","analyzedSha":"6f52dcdf99e282ef7a7db68c81301fa4618d0f79","analyzedAt":"2026-08-22T10:14:23.840Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}