jdx/mise · error

brew-cask: refusing to restore flight target through a chang

Error message

brew-cask: refusing to restore flight target through a changed parent: {}

What it means

Before restoring a flight backup, validate_backup_parents recomputes the resolved parent directory of both the target and (if present) the backup and compares them with the parents recorded when the backup was taken. A mismatch (parent replaced, moved, or re-symlinked in the meantime) aborts the restore so the original is not written into the wrong location.

Source

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

fn resolved_parent(path: &Path) -> Result<PathBuf> {
    let parent = path
        .parent()
        .ok_or_else(|| eyre!("brew-cask: flight target has no parent"))?;
    Ok(path_with_resolved_existing_ancestor(parent))
}

fn validate_backup_parents(entry: &ArtifactLinkBackup) -> Result<()> {
    if resolved_parent(&entry.target)? != entry.target_parent
        || entry
            .backup
            .as_deref()
            .zip(entry.backup_parent.as_ref())
            .is_some_and(|(backup, expected)| {
                !resolved_parent(backup).is_ok_and(|current| current == *expected)
            })
    {
        bail!(
            "brew-cask: refusing to restore flight target through a changed parent: {}",
            entry.target.display()
        );
    }
    Ok(())
}

fn flight_backup_parent(target: &Path) -> Result<&Path> {
    if let Some(app) = target.ancestors().find(|ancestor| {
        ancestor
            .extension()
            .is_some_and(|extension| extension.eq_ignore_ascii_case("app"))
    }) {
        return app
            .parent()
            .ok_or_else(|| eyre!("brew-cask: app flight target has no parent"));
    }
    target

View on GitHub (pinned to 9dcfcaa0dc)

Solutions

  1. Restore the original parent directory (recreate it, or move it back) so its resolved path matches the recorded parent, then retry
  2. Otherwise restore manually: copy the backup file to the intended location and delete the recovery record
  3. Avoid restructuring directories that contain in-flight cask artifacts
Defensive patterns

Strategy: validation

Validate before calling

use std::fs;

fn backup_parents_unchanged(target: &std::path::Path, backup: Option<&std::path::Path>,
                            expected_target_parent: &std::path::Path) -> bool {
    fs::canonicalize(target.parent().unwrap_or_default())
        .is_ok_and(|p| p == expected_target_parent)
        && backup
            .map(|b| fs::canonicalize(b.parent().unwrap_or_default()).is_ok())
            .unwrap_or(true)
}

Try / catch

match recover_flight_backups() {
    Err(e) if e.to_string().contains("changed parent") => {
        // recreate/move the original parent directory back, then retry recovery
        return Err(e.wrap_err("restore the original parent dir, then re-run recovery"));
    }
    other => other?,
}

Prevention

When it happens

Trigger: The parent directory of an app/artifact was deleted and recreated, renamed, or had a symlink inserted between the interrupted run and the recovery attempt.

Common situations: User reorganized ~/Applications or the Homebrew prefix between a crashed install and the retry; another installer rebuilt the directory; migration tools moving app containers around.

Related errors


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