{"record":{"id":"7ca829cd6a19c36f","repo":"astrid-runtime/astrid","slug":"durable-capsule-id-disappeared-after-publish","errorCode":null,"errorMessage":"durable capsule {id} disappeared after publish","messagePattern":"durable capsule (.+?) disappeared after publish","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/astrid-capsule-install/src/storage.rs","lineNumber":486,"sourceCode":"        .context(\"stage verified durable capsule package\")?;\n\n    // Storage-backed installs initially assemble a lifecycle workspace that\n    // intentionally omits the WASM component. Replace it with the complete\n    // verified package before publication so an immediately triggered live\n    // reload sees the same bytes that a restart would rematerialize.\n    let previous_target = materialization.path().join(\"previous\");\n    fs::rename(target_dir, &previous_target)\n        .context(\"stage incomplete capsule install cache for replacement\")?;\n    if let Err(error) = fs::rename(&staged_target, target_dir) {\n        let _ = fs::rename(&previous_target, target_dir);\n        return Err(error).context(\"publish verified capsule materialization\");\n    }\n\n    registry\n        .install(&owner, &id, &package, expected)\n        .with_context(|| format!(\"publish durable capsule package {id} for {principal}\"))?;\n    read_verified_durable_package(store, uid, &id)?\n        .ok_or_else(|| anyhow::anyhow!(\"durable capsule {id} disappeared after publish\"))?;\n    Ok(())\n}\n\n/// Publish a package when the caller already has canonical bytes.\n///\n/// This is used by archive migration and by tests that have no source\n/// directory to materialize. The caller must provide the immutable principal\n/// UID, so alias reuse cannot redirect the package to a different owner.\npub fn publish_package(\n    store: &Arc<RuntimePrincipalStore>,\n    uid: astrid_core::identity::PrincipalUid,\n    id: &str,\n    package: &CapsulePackage,\n) -> anyhow::Result<()> {\n    let owner = StateOwner::Principal(uid);\n    let registry = store.capsules();\n    let expected = registry\n        .get_snapshot(&owner, id)?","sourceCodeStart":468,"sourceCodeEnd":504,"githubUrl":"https://github.com/astrid-runtime/astrid/blob/affd8760f44190dbdfbec23403f4c4b642c33112/crates/astrid-capsule-install/src/storage.rs#L468-L504","documentation":"publish_directory_package installs the package into the registry and then immediately re-reads it with read_verified_durable_package to confirm the publish landed. If the verification read returns None — the capsule is absent right after a successful install call — this error reports the post-publish inconsistency instead of silently succeeding.","triggerScenarios":"registry.install reports success but read_verified_durable_package(store, uid, id) cannot find the capsule: concurrent removal between install and read, the install silently writing to a different owner/uid scope than the read, or a corrupted/rolled-back store.","commonSituations":"Two processes publishing/removing the same capsule concurrently; mismatched principal/uid parameters between install and verification; storage backends with eventual consistency or failing writes that install did not surface.","solutions":["Re-run the publish; transient races or temporary storage failures usually clear.","Check that the owner/principal and uid passed to publish_directory_package match the scope you later read from.","Inspect the registry store for the capsule (list by owner) to see whether the install actually landed.","Rule out concurrent processes mutating the same store; serialize publish operations.","If reproducible, check registry.install's write path/storage backend for silent failures and repair the store."],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"match publish_directory_package(/* ... */) {\n    Err(e) if e.to_string().contains(\"disappeared after publish\") => {\n        // verify scope params, then retry once\n        std::thread::sleep(std::time::Duration::from_millis(250));\n        publish_directory_package(/* same args */)?\n    }\n    other => other?,\n}","preventionTips":["Ensure owner/principal/uid arguments are consistent between install and verification.","Serialize publish and remove operations against the same store.","Check the storage backend for silent write failures or eventual-consistency semantics.","List the registry after failures to confirm whether the package actually landed."],"tags":["publish","consistency","race-condition"],"backgroundTag":"internal-invariant-violation","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"}