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 (rollback or crash recovery), mise re-resolves the parent directories of both the target and the backup and compares them to the parents recorded when the transaction started. If either parent changed (renamed, replaced by a symlink, on a different volume after mount changes), mise refuses to restore, because renaming through the changed parent could place the original in the wrong location or follow an attacker-controlled symlink.
Source
Thrown at src/system/packages/brew/cask/flight.rs:541
}
pub(super) 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))
}
pub(super) fn validate_backup_parents(entry: &ArtifactLinkBackup) -> Result<()> {
let backup_parent_matches = match (&entry.backup, &entry.backup_parent) {
(Some(backup), Some(expected)) => {
resolved_parent(backup).is_ok_and(|current| current == *expected)
}
(None, None) => true,
_ => false,
};
if resolved_parent(&entry.target)? != entry.target_parent || !backup_parent_matches {
bail!(
"brew-cask: refusing to restore flight target through a changed parent: {}",
entry.target.display()
);
}
Ok(())
}
pub(super) 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"));
}
targetView on GitHub (pinned to afd2eddd3a)
Solutions
- Restore the original directory layout (recreate/rename the parent directory recorded in the recovery record) and retry the install.
- Manually move the backup file from its backup location back to the intended target, then delete the .recovery record.
- Remove unwanted symlinks in the parent path so parent resolution matches the recorded parent.
- If the layout change is intentional, discard the backup and stale recovery record and reinstall the cask fresh.
Defensive patterns
Strategy: retry
Validate before calling
// verify the target's parent still resolves where you expect before retrying recovery readlink -f "$(dirname "$TARGET_PATH")"
Try / catch
// recovery can legitimately fail while layout is mid-change; retry after fixing parents
loop {
match recover_flight_backups() {
Err(e) if e.to_string().contains("changed parent") => {
restore_original_parent_layout()?; // user action: undo rename/symlink swap
continue;
}
other => break other,
}
} Prevention
- Don't rename or symlink-swap the app's containing directory between a failed install and its retry.
- Keep appdir mounts (network volumes) attached until install/rollback completes.
- If layout must change, discard the stale backup + recovery record and reinstall fresh.
When it happens
Trigger: validate_backup_parents, called from rollback or recover_flight_backup, finds resolved_parent(target) != recorded target_parent, or the backup's resolved parent differs from recorded backup_parent, or backup/backup_parent presence is inconsistent (one set, other None).
Common situations: The user (or another installer) renamed/moved the app's containing directory between the failed install and the retry; a symlink swap on /Applications or a custom appdir; a network volume mount point changed; recovery attempted long after layout changed.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- directory contents cannot be verified safely; left untouched
- invalid recovery destination
- brew-cask:{}: git only_path must name a directory within the
- brew-cask: unresolved recovery for {} still preserves its or
- brew-cask: unresolved recovery for newly created target {}
AI-assisted analysis of jdx/mise@afd2eddd3a (2026-09-09).
Data as JSON: /api/errors/89688e17a6cb47fa.
Report an issue: GitHub.