{"record":{"id":"f7975b7b16522ab2","repo":"astrid-runtime/astrid","slug":"authoritative-principal-store-is-unavailable","errorCode":null,"errorMessage":"authoritative principal store is unavailable","messagePattern":"authoritative principal store is unavailable","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/astrid-kernel/src/lib.rs","lineNumber":3252,"sourceCode":"\n    /// Atomically remove one capsule package from the authenticated owner's\n    /// durable registry, then tear down the corresponding live view. Native\n    /// install directories are never consulted or deleted by this path.\n    ///\n    /// # Errors\n    ///\n    /// Returns an error when the durable store or owner mapping is unavailable,\n    /// the registry mutation fails, or the live view cannot be unloaded.\n    #[cfg(not(target_family = \"wasm\"))]\n    pub(crate) async fn remove_one_capsule(\n        &self,\n        id: &astrid_capsule_types::CapsuleId,\n        principal: &PrincipalId,\n    ) -> Result<bool, anyhow::Error> {\n        let store = self\n            .principal_store\n            .clone()\n            .ok_or_else(|| anyhow::anyhow!(\"authoritative principal store is unavailable\"))?;\n        let uid = self\n            .principal_directory\n            .uid_for(principal)\n            .map_err(|error| anyhow::anyhow!(\"resolve durable owner for {principal}: {error}\"))?;\n        let owner = astrid_storage::StateOwner::Principal(uid);\n        let snapshot = store\n            .capsules()\n            .get_snapshot(&owner, id.as_str())\n            .map_err(|error| anyhow::anyhow!(\"read durable capsule package '{id}': {error}\"))?;\n        if snapshot.is_none() {\n            return Ok(false);\n        }\n        // Quiesce and unload before deleting the durable package. If unload\n        // fails, the package remains authoritative and can be retried on the\n        // next request; no live runtime is left without its registry source.\n        let _ = self.unload_one_capsule(id, principal).await?;\n        let removed = match store.capsules().remove(&owner, id.as_str()) {\n            Ok(removed) => removed,","sourceCodeStart":3234,"sourceCodeEnd":3270,"githubUrl":"https://github.com/astrid-runtime/astrid/blob/affd8760f44190dbdfbec23403f4c4b642c33112/crates/astrid-kernel/src/lib.rs#L3234-L3270","documentation":"Thrown in `remove_one_capsule` when the kernel's `principal_store` field is `None`. The principal store is the authoritative durable registry of capsule packages; without it the kernel cannot read or delete durable state, so removal is refused instead of operating on a stale or in-memory-only view. This is a startup/initialization invariant: the store should be attached before any capsule administration is attempted.","triggerScenarios":"Calling `remove_one_capsule` on a kernel instance constructed without a durable principal store (store attach failed, was skipped in an embedded/test configuration, or the kernel is running in a degraded mode where the store handle was never wired up).","commonSituations":"Embedding astrid-kernel in a harness or test that builds the kernel without persistent storage; a failed storage backend initialization silently leaving the store `None`; running a native build against a misconfigured storage path so store attachment never completes before an admin delete request arrives.","solutions":["Ensure the kernel is initialized with a durable principal store before accepting capsule removal requests (check the store-attach step for silent failures).","Guard callers: check whether the durable store is configured before invoking `remove_one_capsule`.","If running in an intentionally ephemeral mode, use in-memory unload (`unload_one_capsule`) instead of durable removal."],"exampleFix":"// before: kernel built without store\nlet kernel = AstridKernel::builder().build()?;\nkernel.remove_one_capsule(&id, &principal).await?;\n// after\nlet kernel = AstridKernel::builder()\n    .with_principal_store(durable_store)\n    .build()?;\nkernel.remove_one_capsule(&id, &principal).await?;","handlingStrategy":"try-catch","validationCode":"fn can_remove_durably(kernel: &Kernel) -> bool { kernel.has_principal_store() }","typeGuard":"fn store_configured(kernel: &Kernel) -> bool { kernel.principal_store().is_some() }","tryCatchPattern":"match kernel.remove_one_capsule(&id, &principal).await {\n    Ok(removed) => info!(\"removed={removed}\"),\n    Err(e) if e.to_string().contains(\"principal store is unavailable\") => {\n        warn!(\"durable store not configured; re-initialize kernel with storage\");\n    },\n    Err(e) => return Err(e),\n}","preventionTips":["Always construct the kernel through a builder/factory that attaches the principal store.","Add an integration smoke test that exercises a durable removal on every startup path.","Fail fast at startup if the durable store is required but absent."],"tags":["rust","storage","kernel","initialization"],"backgroundTag":"missing-required-config","analyzedSha":"affd8760f44190dbdfbec23403f4c4b642c33112","analyzedAt":"2026-09-09T21:28:12.402Z","contentChangedAt":"2026-09-09T21:28:12.402Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}