jdx/mise · error
brew-cask: generic artifact backup changed directories
Error message
brew-cask: generic artifact backup changed directories
What it means
When mise backs up or restores a generic cask artifact via rename, it requires that both source and target live in the same directory (rename cannot cross filesystems/directories). If from.parent() differs from to.parent(), the backend refuses rather than silently falling back to an unsafe copy. This keeps backup/restore of trusted targets inside the validated parent directory.
Solutions
- Reinstall the cask so artifact and backup paths are recomputed consistently under the same parent directory.
- Ensure the computed backup/restore path is in the same directory as the artifact (same parent) before triggering upgrade/rollback.
- Clear stale artifact records from a previous prefix layout and reinstall.
- Report the internal inconsistency if it persists with default configuration — it indicates a backend path-computation bug.
Example fix
// before
let backup = prefix.join("backups").join(name); // different parent
// after
let backup = artifact.parent().unwrap().join(format!("{}.bak", name)); // same parent Defensive patterns
Strategy: try-catch
Validate before calling
if backup.parent() != artifact.parent() {
eprintln!("backup path must share the artifact's parent directory");
std::process::exit(1);
} Type guard
fn same_parent(a: &std::path::Path, b: &std::path::Path) -> bool {
a.parent() == b.parent()
} Prevention
- Compute backup paths from the artifact's own parent, never a separate backups dir.
- Reinstall casks after prefix relocations so paths stay consistent.
- Do not hand-edit artifact records.
- Report persistent mismatches as a backend bug with default config.
When it happens
Trigger: rename_trusted_generic_target is called with 'from' and 'to' paths whose parent directories differ; a backup path is computed in a different directory than the artifact; the source has no parent (root-level path).
Common situations: Internal misconfiguration where the backup dir differs from the artifact dir; artifacts recorded in a stale location from an older install so the computed backup path lands elsewhere; prefix migrations changing directory layouts between record time and operation time.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
- brew-cask: generic artifact backup changed directories
- brew-cask: generic artifact source has no filename
- brew-cask: generic artifact target
- brew-cask: refusing operation through a changed generic…
- brew-cask: refusing to remove generic artifact outside
AI-assisted analysis of jdx/mise@533346cc37 (2026-09-17).
Data as JSON: /api/errors/60d76e5bb70f72ba.
Report an issue: GitHub.
Appendix: source
Thrown at src/system/packages/brew/cask/mod.rs:2549
fn validate_trusted_operation_parent(
parent: &TrustedOperationParent,
expected_parent: &Path,
) -> Result<()> {
let actual_parent = std::fs::canonicalize(parent.path()?)?;
if actual_parent != expected_parent {
bail!(
"brew-cask: refusing operation through a changed generic artifact parent: {}",
expected_parent.display()
);
}
Ok(())
}
fn rename_trusted_generic_target(from: &Path, to: &Path, expected_parent: &Path) -> Result<()> {
#[cfg(unix)]
{
if from.parent() != to.parent() {
bail!("brew-cask: generic artifact backup changed directories");
}
let parent = open_trusted_operation_parent(from, true, false)?;
validate_trusted_operation_parent(&parent, expected_parent)?;
let from_name = from
.file_name()
.ok_or_else(|| eyre!("brew-cask: generic artifact source has no filename"))?;
let to_name = to
.file_name()
.ok_or_else(|| eyre!("brew-cask: generic artifact target has no filename"))?;
nix::fcntl::renameat(&parent.fd, from_name, &parent.fd, to_name)?;
Ok(())
}
#[cfg(not(unix))]
{
let _ = expected_parent;
file::rename(from, to)
}
}View on GitHub (pinned to 533346cc37)