{"record":{"id":"50ecb15cedb55f70","repo":"astrid-runtime/astrid","slug":"capsule-cache-owner-or-id-does-not-match-authentic","errorCode":null,"errorMessage":"capsule cache owner or id does not match authenticated registry scope","messagePattern":"capsule cache owner or id does not match authenticated registry scope","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/astrid-kernel/src/lib.rs","lineNumber":1604,"sourceCode":"            .map_err(|error| anyhow::anyhow!(\"capsule cache path is redirected: {error}\"))?;\n        let components: Vec<String> = relative\n            .components()\n            .map(|component| match component {\n                std::path::Component::Normal(value) => Ok(value.to_string_lossy().into_owned()),\n                _ => Err(anyhow::anyhow!(\n                    \"capsule cache path contains unsafe components\"\n                )),\n            })\n            .collect::<anyhow::Result<_>>()?;\n        if components.len() != 3 {\n            anyhow::bail!(\"capsule cache path does not contain owner/id/digest components\");\n        }\n        let uid = self\n            .principal_directory\n            .uid_for(principal)\n            .map_err(|error| anyhow::anyhow!(\"resolve capsule cache owner UID: {error}\"))?;\n        if components[0] != uid.to_string() || components[1] != manifest.package.name {\n            anyhow::bail!(\"capsule cache owner or id does not match authenticated registry scope\");\n        }\n        let digest = blake3::hash(&snapshot.package().archive)\n            .to_hex()\n            .to_string();\n        if components[2] != digest {\n            anyhow::bail!(\"materialized capsule digest does not match durable registry\");\n        }\n        Ok(())\n    }\n\n    /// Inventory a projection without traversing redirects or special files.\n    #[cfg(not(all(target_arch = \"wasm32\", target_os = \"unknown\")))]\n    fn inventory_projection_files(root: &Path) -> anyhow::Result<ProjectionInventory> {\n        fn walk(\n            root: &Path,\n            directory: &Path,\n            inventory: &mut ProjectionInventory,\n        ) -> anyhow::Result<()> {","sourceCodeStart":1586,"sourceCodeEnd":1622,"githubUrl":"https://github.com/astrid-runtime/astrid/blob/affd8760f44190dbdfbec23403f4c4b642c33112/crates/astrid-kernel/src/lib.rs#L1586-L1622","documentation":"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).","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before: shared cache across principals\nlet cache_root = Path::new(\"/var/cache/astrid/capsules\");\n\n// after: per-principal cache scope\nlet uid = kernel.principal_directory().uid_for(&principal)?;\nlet cache_root = Path::new(\"/var/cache/astrid/capsules\").join(uid.to_string());","handlingStrategy":"validation","validationCode":"let uid = kernel.principal_directory().uid_for(&principal)?;\nif !cache_entry.starts_with(cache_root.join(uid.to_string())) {\n    return Err(\"cache entry belongs to a different principal\");\n}","typeGuard":null,"tryCatchPattern":"match result {\n    Err(e) if e.to_string().contains(\"authenticated registry scope\") => {\n        // re-authenticate as the owning principal or purge the cache entry\n    }\n    other => other?,\n}","preventionTips":["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"],"tags":["cache","auth","ownership","capsule","security"],"backgroundTag":"permission-denied","analyzedSha":"affd8760f44190dbdfbec23403f4c4b642c33112","analyzedAt":"2026-09-09T21:28:12.402Z","contentChangedAt":"2026-09-09T21:28:12.402Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}