astrid-runtime/astrid · error
capsule cache owner or id does not match authenticated…
Error message
capsule cache owner or id does not match authenticated registry scope
What it means
This error means the cache directory's owner (uid) or package id component did not match the currently authenticated principal's uid or the manifest's package name. The kernel throws it to enforce that a capsule cache entry can only be used by the registry identity that owns it — preventing a capsule from being materialized out of another principal's cache slot (cross-tenant cache confusion).
Solutions
- Clear the capsule cache (or the specific owner/id entry) and re-materialize under the current authenticated principal
- Verify the authenticated principal is the one that originally populated the cache; log in with the intended registry identity
- Ensure the manifest's package.name matches the cache directory's id component — fix the manifest or the cache dir to agree
- In shared/CI environments, scope the cache per-principal (e.g. include uid in the cache key) instead of sharing one cache root
Example fix
// before: shared cache across principals
let cache_root = Path::new("/var/cache/astrid/capsules");
// after: per-principal cache scope
let uid = kernel.principal_directory().uid_for(&principal)?;
let cache_root = Path::new("/var/cache/astrid/capsules").join(uid.to_string()); Defensive patterns
Strategy: validation
Validate before calling
let uid = kernel.principal_directory().uid_for(&principal)?;
if !cache_entry.starts_with(cache_root.join(uid.to_string())) {
return Err("cache entry belongs to a different principal");
} Try / catch
match result {
Err(e) if e.to_string().contains("authenticated registry scope") => {
// re-authenticate as the owning principal or purge the cache entry
}
other => other?,
} Prevention
- Scope cache directories per principal/uid
- Purge cache when switching registry identities
- Keep manifest package.name in sync with the cache id directory
- In CI, namespace cached volumes by principal
When it happens
Trigger: The cache path validation finds components[0] != uid_for(principal) or components[1] != manifest.package.name — e.g. authenticating as a different user than the one whose cache was populated, or loading a manifest whose package name differs from the cache directory name.
Common situations: Switching registry accounts/identities while reusing a shared cache directory; renaming a package in Capsule.toml without clearing the cache; running the kernel under a different OS user (different uid) on a shared machine; CI reusing a cached volume from a job with a different principal.
Understand the failure class
Background: Permission denied / not authorized / 403 Forbidden: access-control rejections when the caller lacks the required role, grant, or ownership — this error's family across 18 libraries.
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
- cache changed to a redirect or special entry
- cache contains a redirect or special entry
- capsule cache path contains unsafe components
- capsule cache path does not contain owner/id/digest…
- capsule cache path is outside the durable registry cache
AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09).
Data as JSON: /api/errors/50ecb15cedb55f70.
Report an issue: GitHub.
Appendix: source
Thrown at crates/astrid-kernel/src/lib.rs:1604
.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.
#[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))]
fn inventory_projection_files(root: &Path) -> anyhow::Result<ProjectionInventory> {
fn walk(
root: &Path,
directory: &Path,
inventory: &mut ProjectionInventory,
) -> anyhow::Result<()> {View on GitHub (pinned to affd8760f4)