jdx/mise · error

brew-cask: unresolved recovery for {} still preserves its or

Error message

brew-cask: unresolved recovery for {} still preserves its original at {}

What it means

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.

Source

Thrown at src/system/packages/brew/cask.rs:3174

        return Ok(());
    };
    for entry in entries.flatten() {
        let path = entry.path();
        if path
            .extension()
            .is_none_or(|extension| extension != "recovery")
        {
            continue;
        }
        let Ok(body) = file::read_to_string(&path) else {
            continue;
        };
        let Ok(record) = serde_json::from_str::<FlightRecoveryRecord>(&body) else {
            continue;
        };
        if record.target == target {
            if let Some(backup) = record.backup {
                bail!(
                    "brew-cask: unresolved recovery for {} still preserves its original at {}",
                    target.display(),
                    backup.display()
                );
            }
            bail!(
                "brew-cask: unresolved recovery for newly created target {}",
                target.display()
            );
        }
    }
    Ok(())
}

fn recover_flight_backups() -> Result<()> {
    let root = flight_recovery_root();
    recover_flight_backups_in(&root)
}

View on GitHub (pinned to 9dcfcaa0dc)

Solutions

  1. Re-run the same cask command: recovery of pending flights runs first and normally completes it
  2. 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
  3. If recovery cannot complete, report it with the record contents

Example fix

# manual cleanup after confirming the target is fine
mv '/path/in/error/backup' '/path/in/error/target'
rm "${XDG_STATE_HOME:-~/.local/state}/mise/brew-cask/flight-recovery/example.recovery"
Defensive patterns

Strategy: retry

Validate before calling

// Before installing over a target, run pending-flight recovery first
let root = flight_recovery_root();
for entry in std::fs::read_dir(&root).ok().into_iter().flatten().flatten() {
    let path = entry.path();
    if path.extension().is_some_and(|e| e == "recovery") {
        recover_flight_backups()?; // complete pending flights before proceeding
        break;
    }
}

Try / catch

match install_cask(&cask) {
    Err(e) if e.to_string().contains("unresolved recovery") => {
        // a previous run was interrupted: complete recovery, then retry once
        recover_flight_backups()?;
        install_cask(&cask)?
    }
    other => other?,
}

Prevention

When it happens

Trigger: 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.

Common situations: Interrupted upgrades; power loss mid-install; users killing the process when it appeared stuck.

Related errors


AI-assisted analysis of jdx/mise@9dcfcaa0dc (2026-08-17). Data as JSON: /api/errors/1d0f7cf6cd7d9a05. Report an issue: GitHub.