astrid-runtime/astrid · error
durable capsule {id} disappeared after publish
Error message
durable capsule {id} disappeared after publish What it means
Thrown by migrate_native_capsules_with_report after a durable capsule is installed into the registry: the immediate get_snapshot readback returned None, meaning the capsule that was just published cannot be found in the registry. This is an internal invariant check — installation reported success but persistence did not survive, so the migration aborts rather than leaving a half-migrated capsule.
Source
Thrown at crates/astrid-capsule-install/src/storage/migration.rs:183
.with_context(|| format!("verify canonical legacy capsule archive {id}"))?;
let mut durable_authority = authority;
verification
.content_digest()
.clone_into(&mut durable_authority.content_digest);
let durable_authority_bytes = serde_json::to_vec_pretty(&durable_authority)
.with_context(|| format!("serialize durable legacy capsule authority {id}"))?;
let package = CapsulePackage::new(archive, meta_bytes, durable_authority_bytes);
let expectation = match registry.get_snapshot(&owner, id)? {
None => CapsuleInstallExpectation::Absent,
Some(snapshot) if snapshot.package() == &package => {
CapsuleInstallExpectation::Generation(snapshot.generation())
},
Some(_) => bail!("durable capsule {id} conflicts with legacy native content"),
};
registry.install(&owner, id, &package, expectation)?;
let readback = registry
.get_snapshot(&owner, id)?
.ok_or_else(|| anyhow::anyhow!("durable capsule {id} disappeared after publish"))?;
if readback.package() != &package {
bail!("durable capsule {id} failed byte-for-byte readback");
}
read_verified_durable_package_for_owner(store, &owner, id)?.ok_or_else(|| {
anyhow::anyhow!("durable capsule {id} failed authoritative verification")
})?;
astrid_core::platform_fs::verify_no_redirects(&target)
.with_context(|| format!("verify legacy capsule {id} before retirement"))?;
let final_archive = canonical_legacy_archive(home, &target, &meta, &manifest)?;
if final_archive != package.archive {
bail!("legacy capsule {id} changed before retirement");
}
if fs::read(target.join("meta.json"))? != package.metadata {
bail!("legacy capsule {id} metadata changed before retirement");
}
if read_installed_authority_bytes(home, &target)?.as_deref()
!= Some(source_authority_bytes.as_slice())
{View on GitHub (pinned to affd8760f4)
Solutions
- Re-run the migration after checking the storage backend for corruption or incomplete writes; the install itself succeeded so state may just need re-publishing
- Verify no concurrent process (GC, compaction, another migration) is running against the same capsule home directory
- Test the storage backend: call install() then get_snapshot() manually and confirm the snapshot survives
- If using a custom RuntimePrincipalStore/registry implementation, fix it so install() is durably persisted before returning
Defensive patterns
Strategy: try-catch
Validate before calling
// before migrating
let pre = registry.get_snapshot(&owner, &id)?;
if pre.is_none() { /* legacy capsule exists but nothing durable yet — proceed */ }
// verify storage writable
std::fs::metadata(store.root())?; Try / catch
match migrate_native_capsules(&home) {
Err(e) if e.to_string().contains("disappeared after publish") => {
// storage dropped the install: check backend health, then retry once
retry_migration_with_fresh_store()?;
}
Err(e) => return Err(e),
Ok(report) => apply(report),
} Prevention
- Do not run GC/compaction or a second migration concurrently with the migration
- Health-check the storage backend (write/read round-trip) before starting migration
- Run migration as the same OS user that owns the capsule store
When it happens
Trigger: Calling migrate_native_capsules / migrate_all_native_capsules_with_report (directly or via the migration tests) when registry.install() succeeds but registry.get_snapshot(&owner, id) returns None for the same owner/id — i.e. the durable store dropped or failed to durably record the entry between write and read.
Common situations: Corrupt or partially-flushed storage backend during migration; concurrent process deleting/compacting the registry while migration runs; a bug in a custom storage implementation that fails to persist install() state; mismatched StateOwner scoping so the snapshot lookup hits a different namespace.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
- durable capsule {id} failed authoritative verification
- unexpected {kind:?} in a canonical File owning closure
- equal chunk identities named different bytes in delta eviden
- encoded evidence delta did not reconstruct its target
- legacy capsule entry has a non-UTF-8 name
AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09).
Data as JSON: /api/errors/4467d4153e1651c4.
Report an issue: GitHub.