astrid-runtime/astrid · error
capsule cache path is outside the durable registry cache
Error message
capsule cache path is outside the durable registry cache
What it means
Static error from `dir.strip_prefix(cache_root)` failing in validate_published_cache_path: the candidate cache directory is not under `<astrid_home>/run/capsules`, so it cannot be a legitimate durable-registry cache path. This is a hard security boundary check with no inner cause.
Solutions
- Ensure the dir passed in was produced by published_cache_target from the same astrid_home
- Check that ASTRID_HOME / astrid_home has not changed between target resolution and validation
- Recompute the cache target instead of passing a user-supplied path
- If using mounts/aliases, use the canonical home path consistently
Example fix
// before validate(&some_user_path, principal, manifest, snapshot)?; // after let target = published_cache_target(principal, manifest, snapshot)?; validate(&target, principal, manifest, snapshot)?;
Defensive patterns
Strategy: validation
Validate before calling
let cache_root = astrid_home.run_dir().join("capsules");
if dir.strip_prefix(&cache_root).is_err() {
panic!("refusing to validate path outside durable cache root: {}", dir.display());
} Type guard
fn inside_cache_root(dir: &Path, home: &AstridHome) -> bool {
dir.strip_prefix(home.run_dir().join("capsules")).is_ok()
} Prevention
- Only pass resolver-produced paths to validate_published_cache_path
- Never accept user-supplied cache directories
- Keep ASTRID_HOME stable for the lifetime of a kernel instance
When it happens
Trigger: validate_published_cache_path is handed a `dir` outside run_dir().join("capsules") — e.g. a path computed from a different home, a tampered registry snapshot, or an absolute path substituted for the computed target.
Common situations: ASTRID_HOME changed between resolution and validation; registry snapshot fields manually edited; code passing an arbitrary directory into the validator; mounted/aliased home producing lexically different paths.
Understand the failure class
Background: Path traversal blocked: "path escapes the workspace" and "outside site root" errors when a path will not stay inside its allowed directory — this error's family across 26 libraries.
Related errors
- capsule cache path contains unsafe components
- capsule cache path is redirected
- cache changed to a redirect or special entry
- cache contains a redirect or special entry
- capsule cache owner or id does not match authenticated…
AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09).
Data as JSON: /api/errors/8dbd21dcb8ad3caf.
Report an issue: GitHub.
Appendix: source
Thrown at crates/astrid-kernel/src/lib.rs:1583
false,
None,
&self.workspace_layout,
)
.map_err(|error| anyhow::anyhow!("resolve durable capsule cache target: {error}"))
}
/// Validate the disposable cache path against an exact owner snapshot.
#[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))]
fn validate_published_cache_path(
&self,
dir: &Path,
principal: &PrincipalId,
manifest: &astrid_capsule_types::manifest::CapsuleManifest,
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)View on GitHub (pinned to affd8760f4)