astrid-runtime/astrid · error
capsule cache path does not contain owner/id/digest…
Error message
capsule cache path does not contain owner/id/digest components
What it means
This error means the capsule cache directory layout under the cache root did not have exactly three path components (owner/id/digest), so the kernel could not verify the cache entry against the authenticated principal and manifest. The library throws it while validating a materialized capsule's cache location, since the owner-uid/package-name/digest structure is required to attribute and integrity-check cached packages.
Solutions
- Clear the capsule cache directory and re-materialize the capsule so the kernel recreates the owner/id/digest layout
- Ensure the kernel/cache being used is the same version that wrote the entries (mixed-version cache layouts cause this)
- Do not hand-move or rename cache subdirectories; let the kernel manage cache layout
- If a script seeds the cache, write entries as <cache-root>/<owner-uid>/<package-name>/<digest>/
Example fix
// before: script seeding cache with wrong layout
fs::copy(archive, cache_root.join("mypackage"))?;
// after: owner-uid/package-name/digest layout
let uid = kernel.principal_directory().uid_for(&principal)?;
let digest = blake3::hash(&archive).to_hex().to_string();
let dir = cache_root.join(uid.to_string()).join("mypackage").join(digest);
fs::create_dir_all(&dir)?;
fs::copy(archive, dir.join("package.capsule"))?; Defensive patterns
Strategy: validation
Validate before calling
let rel = cache_entry.strip_prefix(cache_root)?;
if rel.components().count() != 3 {
return Err("cache entry must be <owner-uid>/<id>/<digest>");
} Try / catch
match result {
Err(e) if e.to_string().contains("owner/id/digest components") => {
// invalidate the cache entry and re-materialize
}
other => other?,
} Prevention
- Let the kernel manage cache layout; never hand-move cache directories
- Use one kernel version per cache directory (avoid mixed-version shared caches)
- If pre-seeding cache, follow the owner-uid/package-name/digest layout exactly
- Clear stale cache after kernel upgrades that change layout
When it happens
Trigger: Invoking the cache-path validation (during materialization from a registry snapshot) with a cache directory whose path, relative to the cache root, yields fewer or more than 3 components — e.g. a cache entry written by an older kernel version with a flat layout, a manually moved/renamed cache dir, or a path passed directly instead of the expected owner/id/digest leaf.
Common situations: Upgrading from an older kernel whose cache layout differed; manually cleaning or restructuring the cache directory by hand; running two kernel versions against a shared cache; a script copying cache entries to the wrong depth.
Understand the failure class
Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.
Related errors
- Astrid volume is not a regular file
- capsule cache owner or id does not match authenticated…
- capsule cache path contains unsafe components
- capsule ' ' exceeds or cannot prove its installed authority
- capsule projection contains a special file
AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09).
Data as JSON: /api/errors/8fa24be5d2712933.
Report an issue: GitHub.
Appendix: source
Thrown at crates/astrid-kernel/src/lib.rs:1597
snapshot: &astrid_storage::CapsulePackageSnapshot,
) -> anyhow::Result<()> {
let cache_root = self.astrid_home.run_dir().join("capsules");
let relative = dir.strip_prefix(&cache_root).map_err(|_| {
anyhow::anyhow!("capsule cache path is outside the durable registry cache")
})?;
astrid_core::platform_fs::verify_no_redirects(dir)
.map_err(|error| anyhow::anyhow!("capsule cache path is redirected: {error}"))?;
let components: Vec<String> = relative
.components()
.map(|component| match component {
std::path::Component::Normal(value) => Ok(value.to_string_lossy().into_owned()),
_ => Err(anyhow::anyhow!(
"capsule cache path contains unsafe components"
)),
})
.collect::<anyhow::Result<_>>()?;
if components.len() != 3 {
anyhow::bail!("capsule cache path does not contain owner/id/digest components");
}
let uid = self
.principal_directory
.uid_for(principal)
.map_err(|error| anyhow::anyhow!("resolve capsule cache owner UID: {error}"))?;
if components[0] != uid.to_string() || components[1] != manifest.package.name {
anyhow::bail!("capsule cache owner or id does not match authenticated registry scope");
}
let digest = blake3::hash(&snapshot.package().archive)
.to_hex()
.to_string();
if components[2] != digest {
anyhow::bail!("materialized capsule digest does not match durable registry");
}
Ok(())
}
/// Inventory a projection without traversing redirects or special files.View on GitHub (pinned to affd8760f4)