astrid-runtime/astrid · error · io::Error
layout migration destination is redirected or not a regular
Error message
layout migration destination is redirected or not a regular file: {} What it means
verify_receipt_destination_authority validates that the migration receipt's recorded destination is an authoritative, unredirected regular file. It reads symlink_metadata on the destination's physical path and rejects it if the entry is a symlink or not a plain file. This guards against a receipt pointing at a path that an attacker or misconfiguration has redirected (e.g. symlink swap) or that was replaced by a directory or other non-file entry.
Source
Thrown at crates/astrid-core/src/dirs_layout_records.rs:183
if actual != expected {
return Err(io::Error::new(
io::ErrorKind::InvalidData,
format!(
"layout migration record is not canonical: {}",
path.display()
),
));
}
Ok(parsed)
}
pub(super) fn verify_receipt_destination_authority(
destination: &LayoutTreeIdentityV1,
) -> io::Result<()> {
let path = physical_path(destination)?;
let metadata = std::fs::symlink_metadata(&path)?;
if metadata.file_type().is_symlink() || !metadata.is_file() {
return Err(io::Error::new(
io::ErrorKind::InvalidData,
format!(
"layout migration destination is redirected or not a regular file: {}",
path.display()
),
));
}
crate::platform_fs::verify_no_redirects(&path)
}
pub(super) fn verify_receipt_destination_is_live_path(
destination: &LayoutTreeIdentityV1,
live_path: &Path,
) -> io::Result<()> {
let parent = live_path.parent().ok_or_else(|| {
io::Error::new(
io::ErrorKind::InvalidInput,
"live Astrid volume has no parent",View on GitHub (pinned to affd8760f4)
Solutions
- Remove the symlink at the destination path and replace it with the real regular file the receipt points to.
- Re-create or re-issue the layout migration receipt so its LayoutTreeIdentityV1 matches the current real on-disk path.
- Inspect the path with `ls -la` / `stat` to see what replaced the regular file and restore it (e.g. from the migration source).
Example fix
// before: destination replaced by symlink ln -s /mnt/other/volume /path/to/astrid-volume // after: real regular file at the destination rm /path/to/astrid-volume cp /mnt/other/volume /path/to/astrid-volume # then re-run retirement
Defensive patterns
Strategy: validation
Validate before calling
let md = std::fs::symlink_metadata(&dest_path)?;
if md.file_type().is_symlink() || !md.is_file() {
return Err("receipt destination is not an unredirected regular file");
} Try / catch
match retire_verified_legacy_source(...) {
Err(e) if e.to_string().contains("redirected or not a regular file") => restore_real_destination_file(),
Err(e) => return Err(e),
Ok(()) => {},
} Prevention
- Never place symlinks on Astrid volume paths; mount real filesystems instead.
- Run `find <dir> -type l` periodically to detect redirected paths.
- Re-issue receipts after any path/restore operation.
When it happens
Trigger: Called from verify_receipt_destination_is_live_path (itself called by retire_verified_legacy_source) whenever the path returned by physical_path(destination) is a symlink, directory, FIFO, socket, or any non-regular file when checked via std::fs::symlink_metadata.
Common situations: The Astrid volume path was replaced by a symlink (e.g. to a mount point or tmpfs alias) after the receipt was written; the destination file was deleted and a directory created with the same name; a backup/restore tool replaced the volume file with a symlink.
Understand the failure class
Background: "is not a compatible type" / "cannot merge" errors: when a value's type doesn't match what the library requires — this error's family across 65 libraries.
Related errors
- layout migration source is redirected or not a directory: {}
- legacy principal home root is not a regular directory: {}
- legacy principal profile is not a regular file: {}
- legacy capsule directory is not a regular directory: {}
- legacy capsule entry is not a regular directory: {}
AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09).
Data as JSON: /api/errors/a43cf4e078b7a937.
Report an issue: GitHub.