astrid-runtime/astrid · error
failed to persist {}: {e}
Error message
failed to persist {}: {e} What it means
pack builds the .shuttle tar+gzip stream into a temp file and then atomically persists it to the requested output path via tmp.persist(out_path). If the persist (rename) fails, the OS error is wrapped as "failed to persist <path>: {e}". The archive itself was built successfully; only the final move onto the destination path failed.
Source
Thrown at crates/astrid-cli/src/commands/distro/shuttle.rs:153
);
}
header.set_size(metadata.len());
header.set_cksum();
let mut file = std::fs::File::open(src).with_context(|| {
format!("failed to open staged capsule {}", src.display())
})?;
tar.append_data(&mut header, &entry.path, &mut file)
.with_context(|| format!("failed to append {} to shuttle", entry.path))?;
},
}
}
let encoder = tar.into_inner().context("failed to finish tar stream")?;
encoder.finish().context("failed to finish gzip stream")?;
}
tmp.persist(out_path)
.map_err(|e| anyhow::anyhow!("failed to persist {}: {e}", out_path.display()))?;
Ok(())
}
/// Unpack a `.shuttle` at `archive_path` into `dest` (a mirror dir),
/// WITHOUT installing anything.
///
/// Mirrors the hardened defense in the capsule unpacker: absolute paths
/// and `..` traversal are refused, symlinks and hard-links are refused,
/// and each member is size-capped. A malformed or truncated archive
/// yields a clean error.
pub(crate) fn unpack(archive_path: &Path, dest: &Path) -> anyhow::Result<()> {
std::fs::create_dir_all(dest)
.with_context(|| format!("failed to create mirror dir {}", dest.display()))?;
let tar_gz = std::fs::File::open(archive_path)
.with_context(|| format!("failed to open shuttle: {}", archive_path.display()))?;
let tar = flate2::read::GzDecoder::new(tar_gz);
let mut archive = tar::Archive::new(tar);View on GitHub (pinned to affd8760f4)
Solutions
- Create the output directory first (mkdir -p on the parent of out_path) and re-run pack.
- Check write permissions on the target directory (and that out_path is not itself a directory).
- Ensure out_path is on the same filesystem as the temp dir, or free disk space if the disk is full.
- Check for mandatory-access-control denials (audit logs) if permissions look correct but the rename still fails.
Example fix
// before
pack(&input, "out/distro.shuttle")?; // fails if out/ doesn't exist
// after
std::fs::create_dir_all("out")?;
pack(&input, "out/distro.shuttle")?; Defensive patterns
Strategy: validation
Validate before calling
let out_path: &Path = out_path.as_ref();
if let Some(parent) = out_path.parent() { std::fs::create_dir_all(parent)?; }
anyhow::ensure!(!out_path.is_dir(), "output path {} is a directory", out_path.display()); Try / catch
match pack(&input, out_path) {
Err(e) if e.to_string().starts_with("failed to persist") => {
eprintln!("cannot write {}: check the directory exists and is writable ({e})", out_path.display());
}
other => other?,
} Prevention
- Always create_dir_all the parent of the output path before packing.
- Run pack as a user with write access to the target directory.
- Keep output paths on the same filesystem as the temp dir; monitor disk space.
When it happens
Trigger: Calling pack with an out_path that cannot be written: parent directory missing, no write permission on the directory, out_path is an existing directory, cross-filesystem persist where rename isn't possible, or the temp file was lost before persist.
Common situations: Typing an output path in a nonexistent directory (e.g. out/shuttle/pkg.shuttle when out/ doesn't exist); running from a read-only or user-mismatched directory in CI; disk full or SELinux/AppArmor blocking the rename.
Understand the failure class
Background: "failed to write file", "Could not save figure", "Error saving remote file" — file write failed: causes and fixes across languages and libraries — this error's family across 38 libraries.
Related errors
- failed to replace signed capsule archive: {error}
- failed to persist {}: {e}
- audit fixture
- non-empty audit
- leftover capsule authority receipt is not a regular file: {}
AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09).
Data as JSON: /api/errors/95af2dc8870b553d.
Report an issue: GitHub.