astrid-runtime/astrid · error
capsule target has no parent
Error message
capsule target has no parent
What it means
publish_directory_package stages a verified package via a temp materialization directory created inside the PARENT of the target directory (so the rename/stage is same-filesystem). If target_dir has no parent (i.e. it is a filesystem root like '/' or an empty relative path resolved to root), the publish cannot create its staging directory and this error is raised.
Source
Thrown at crates/astrid-capsule-install/src/storage.rs:463
)
})?;
let authority = serde_json::to_vec_pretty(&durable_authority)
.context("serialize installed capsule authority receipt")?;
let registry = store.capsules();
let owner = StateOwner::Principal(uid);
let id = authority_capsule_id(&authority)?;
let expected = registry
.get_snapshot(&owner, &id)?
.map_or(CapsuleInstallExpectation::Absent, |snapshot| {
CapsuleInstallExpectation::Generation(snapshot.generation())
});
let package = CapsulePackage::new(archive, metadata, authority);
let materialization = tempfile::Builder::new()
.prefix(".capsule-materialization-")
.tempdir_in(
target_dir
.parent()
.ok_or_else(|| anyhow::anyhow!("capsule target has no parent"))?,
)
.context("stage verified durable capsule materialization")?;
let staged_target = materialization.path().join("package");
materialize_capsule_package(&package, &staged_target)
.context("stage verified durable capsule package")?;
// Storage-backed installs initially assemble a lifecycle workspace that
// intentionally omits the WASM component. Replace it with the complete
// verified package before publication so an immediately triggered live
// reload sees the same bytes that a restart would rematerialize.
let previous_target = materialization.path().join("previous");
fs::rename(target_dir, &previous_target)
.context("stage incomplete capsule install cache for replacement")?;
if let Err(error) = fs::rename(&staged_target, target_dir) {
let _ = fs::rename(&previous_target, target_dir);
return Err(error).context("publish verified capsule materialization");
}
View on GitHub (pinned to affd8760f4)
Solutions
- Pass a real capsule target directory that has a parent, e.g. ~/.astrid/capsules/<name> rather than / .
- Fix path-building code that normalizes the target down to the root; keep at least one directory component.
- Validate the target path before publishing (target.is_absolute() && target.parent().is_some()).
- If publishing to a mount, use a subdirectory of the mount instead of the mount root.
Example fix
// before
publish_directory_package(store, registry, "/", /* ... */)?;
// after
let target = PathBuf::from("/var/lib/capsules/my-capsule");
publish_directory_package(store, registry, &target, /* ... */)?; Defensive patterns
Strategy: validation
Validate before calling
fn ensure_publishable_target(target: &std::path::Path) -> anyhow::Result<()> {
if target.parent().is_none() {
anyhow::bail!("target {:?} must have a parent directory", target);
}
Ok(())
} Prevention
- Never pass '/' or a bare mount root as the capsule target directory.
- Keep at least one directory component in generated target paths.
- Assert target.parent().is_some() in tests that exercise publish.
When it happens
Trigger: Calling publish_directory_package with target_dir = '/' or another path whose parent() returns None — e.g. publishing directly to a mount point root or passing an empty/normalized-to-root target path.
Common situations: Misconfigured install target pointing at the filesystem root; a script building the target path with join/normalize logic that strips all components; tests passing Path::new("/").
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- capsule source is neither a directory nor a regular file: {}
- Source path does not exist: {source}
- source path does not exist: {source}
- mountpoint is not a directory: {}
- leftover capsule authority receipt has no file name: {}
AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09).
Data as JSON: /api/errors/a853020bef3d0d05.
Report an issue: GitHub.