astrid-runtime/astrid · error
invalid destination parent
Error message
invalid destination parent {destination_parent:?}: {error} What it means
Raised by preflight_entry while walking destination parent directories: a non-empty destination_parent string fails FilesystemPath::new conversion. Ensures each ancestor of the destination is a valid logical path before creating it.
Solutions
- Inspect the receipt entry whose destination produces an invalid parent
- Fix the destination string so its parent segments are valid logical path components
- Regenerate the receipt if hand edits broke it
- Ensure paths use the logical '/' separator with relative components only
Example fix
// before: absolute destination yields bad parent "destination": "/abs/path/file" // after: relative logical destination "destination": "abs/path/file"
Defensive patterns
Strategy: validation
Validate before calling
fn parent_is_valid(dest: &str) -> bool {
let parent = dest.rsplit_once('/').map_or(String::new, |(p, _)| p.to_owned());
parent.is_empty() || FilesystemPath::new(parent).is_ok()
} Type guard
fn parse_parent(dest: &str) -> Option<FilesystemPath> {
dest.rsplit_once('/').map(|(p, _)| p.to_string()).filter(|p| !p.is_empty()).and_then(|p| FilesystemPath::new(p).ok())
} Try / catch
if let Err(e) = preflight_entry(...) {
if e.kind() == io::ErrorKind::InvalidData {
return Err(anyhow!("receipt destination structure invalid: {e}"));
}
return Err(e.into());
} Prevention
- Keep destinations relative so derived parents are valid logical paths
- Avoid Windows separators or absolute prefixes in receipt destinations
- Validate both destination and its parent chain before migration
When it happens
Trigger: Calling migrate_one_principal -> preflight_entry when a derived destination parent (computed by rsplit_once('/')) yields an invalid logical path, e.g. when the entry destination contains characters or structure FilesystemPath rejects.
Common situations: Receipts whose source/destination use Windows-style separators or absolute paths, edited receipts, or destinations mixing '/' conventions the logical path layer rejects.
Understand the failure class
Background: "Invalid URL" errors: why new URL(), URI.parse, and reqwest::Url reject your string — missing scheme, whitespace, and bad path format — this error's family across 39 libraries.
Related errors
- invalid logical destination
- invalid receipt destination
- absent migration source has a digest
- cannot migrate an Astrid home without a layout-version…
- destination proof is missing its payload
AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09).
Data as JSON: /api/errors/5f7a27f26b681502.
Report an issue: GitHub.
Appendix: source
Thrown at crates/astrid-kernel/src/principal_home_migration/mod.rs:647
},
Err(FilesystemError::NotFound(_)) => {},
Err(error) => return Err(storage_error(&error)),
},
}
// A missing destination ancestor is allowed only when its corresponding
// source ancestor is a directory that this migration will publish. Walk
// all the way to `home` so an existing file at a higher ancestor cannot be
// hidden by a missing child lookup.
let mut destination_parent = destination
.as_str()
.rsplit_once('/')
.map_or_else(String::new, |(parent, _)| parent.to_owned());
let source_path = source_root.join(&entry.source);
let mut source_parent = source_path.parent().map(Path::to_path_buf);
while !destination_parent.is_empty() {
let parent_path = FilesystemPath::new(destination_parent.clone()).map_err(|error| {
io::Error::new(
io::ErrorKind::InvalidData,
format!("invalid destination parent {destination_parent:?}: {error}"),
)
})?;
match filesystem.stat(&parent_path) {
Ok(existing) if existing.kind() == FilesystemEntryKind::Directory => {},
Ok(_) => {
return Err(conflict_fs(
&parent_path,
"destination parent is not a directory",
));
},
Err(FilesystemError::NotFound(_)) => {
let source_parent_path = source_parent.as_deref().ok_or_else(|| {
conflict_fs(&parent_path, "destination parent has no source directory")
})?;
let metadata = fs::symlink_metadata(source_parent_path)?;
if metadata.file_type().is_symlink() || !metadata.is_dir() {View on GitHub (pinned to affd8760f4)