jdx/mise · error
brew-cask: refusing to restore flight target through a…
Error message
brew-cask: refusing to restore flight target through a changed parent: {} What it means
validate_backup_parents runs during crash recovery of flight backups. It re-resolves the parent directory of the recorded target — and of the backup, if any — and compares against the parents recorded when the backup was taken (resolved_parent on both sides). A mismatch means the directory now reachable at that path is not the one the backup was made in (replaced, renamed, or reached through a different symlink), so restoring through it is refused.
Solutions
- Restore the parent directory to its original identity — remove replacement symlinks or move the real directory back — then re-run
- If the original parent is gone for good, restore the backup file by hand (cp/mv to the desired location) and delete the .recovery record
- Re-run the brew command after the parent path is stable
- Avoid renaming the appdir or prefix while recovery records are pending
Example fix
# before: parent replaced by a symlink $ ls -ld ~/Applications -> link to /Volumes/Extra/Applications # after $ rm ~/Applications && mkdir ~/Applications $ mise brew install --cask foo # recovery proceeds
Defensive patterns
Strategy: retry
Validate before calling
// Before recovery, confirm recorded parents still resolve identically.
fn parent_still_matches(record: &FlightRecoveryRecord) -> bool {
std::fs::canonicalize(record.target.parent().unwrap_or(Path::new("/")))
.map(|p| p == record.target_parent)
.unwrap_or(false)
&& record.backup_parent.as_ref().map(|expected| {
std::fs::canonicalize(record.backup.as_deref().unwrap().parent().unwrap())
.map(|p| p == *expected).unwrap_or(false)
}).unwrap_or(true)
} Try / catch
match recover() {
Err(e) if e.to_string().contains("changed parent") => {
// restore the original parent directory identity, then retry recovery
restore_parent_identity();
recover()
}
other => other,
} Prevention
- Don't rename, move, or symlink the appdir/prefix while recovery records are pending
- After a crash, stabilize the directory layout before re-running brew commands
- If the original parent is unrecoverable, restore backup files by hand and clear the records
When it happens
Trigger: The target's parent directory was unlinked/recreated (different inode) or a symlinked ancestor such as the appdir or Homebrew prefix was retargeted between the interrupted operation and the recovery run; validate_backup_parents then fails for that ArtifactLinkBackup entry.
Common situations: App directory moved or restructured after a crash; switching between /Applications and ~/Applications; prefix symlink changes; overlay/container filesystems remounting parent directories.
Related errors
- brew-cask: binary artifact
- brew-cask: completion target
- brew-cask: completion target
- brew-cask: : Homebrew took ownership of this cask while…
- brew-cask: refusing elevated operation because target…
AI-assisted analysis of jdx/mise@6f52dcdf99 (2026-08-22).
Data as JSON: /api/errors/f29e20b7baea0ee3.
Report an issue: GitHub.
Appendix: source
Thrown at src/system/packages/brew/cask.rs:3447
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"));
}
targetView on GitHub (pinned to 6f52dcdf99)