astrid-runtime/astrid · error
capsule {} disappeared during durable contracts scan
Error message
capsule {} disappeared during durable contracts scan What it means
durable_contracts_pin iterates the authoritative capsule registry for an owner and reads each capsule's verified durable package. If registry.list returns a summary whose package cannot be read back (read_verified_durable_package_for_owner returns None), the registry is inconsistent — a listed capsule vanished mid-scan — so the library aborts with this error instead of computing a skew verdict from incomplete data.
Source
Thrown at crates/astrid-capsule-install/src/contracts.rs:91
== Some(CONTRACTS_WIT_BASENAME)
})
.min_by(|a, b| a.0.cmp(b.0))
.map(|(_, hash)| hash)
}
/// Return the plurality of the daemon fleet's contracts pins from its authoritative owner-root registry.
/// The package metadata and archive are read from one durable snapshot per
/// capsule; no native `.local/capsules` directory or cache is consulted.
pub fn durable_contracts_pin(
store: &RuntimePrincipalStore,
owner: &StateOwner,
) -> anyhow::Result<Option<String>> {
let registry = store.capsules();
let mut counts = std::collections::BTreeMap::<String, usize>::new();
for summary in registry.list(owner)? {
let Some(package) = read_verified_durable_package_for_owner(store, owner, summary.id())?
else {
bail!(
"capsule {} disappeared during durable contracts scan",
summary.id()
);
};
let Some(pin) = contracts_pin(&package.metadata().wit_files) else {
continue;
};
if !is_blake3_pin(pin) {
bail!(
"durable capsule {} has malformed contracts pin",
summary.id()
);
}
let Some(relative) = package
.metadata()
.wit_files
.keys()
.filter(|relative| {View on GitHub (pinned to affd8760f4)
Solutions
- Re-run the contracts refresh once no other astrid operation is mutating the store — transient races resolve on retry
- Run the store's repair/prune command (or reinstall the missing capsule) to reconcile the registry with the durable packages
- Check disk space and store-directory permissions; an interrupted write can leave a summary without a package
- Back up and rebuild the principal store if the inconsistency persists across runs
Example fix
// before $ astrid contracts refresh # while another terminal runs: astrid uninstall my-capsule error: capsule my-capsule disappeared during durable contracts scan // after $ astrid uninstall my-capsule # finish first $ astrid contracts refresh # single writer -> succeeds
Defensive patterns
Strategy: retry
Validate before calling
// ensure no concurrent store writers before scanning
let lock = acquire_store_lock(owner)?; // advisory exclusive lock across astrid processes
let ids: Vec<_> = store.capsules().list(owner)?.iter().map(|s| s.id().to_string()).collect();
for id in &ids {
if read_verified_durable_package_for_owner(store, owner, id)?.is_none() {
anyhow::bail!("package missing for {} before scan", id);
}
} Try / catch
loop {
match durable_contracts_pin(store, owner) {
Ok(pin) => break Ok(pin),
Err(e) if e.to_string().contains("disappeared during durable contracts scan") && retries < 3 => {
retries += 1;
std::thread::sleep(Duration::from_millis(200 * retries));
},
Err(e) => break Err(e),
}
} Prevention
- Never run capsule uninstall/prune concurrently with contracts refresh on the same store
- Check disk space and store permissions; interrupted writes cause missing packages
- Repair or reinstall capsules whose registry entries lack durable packages
- Hold an exclusive store lock for the duration of the scan
When it happens
Trigger: Calling refresh_canonical_contracts_from_registry → durable_contracts_pin when a capsule summary exists in the registry but its durable package is unreadable/unverifiable at contracts.rs:89-95 — e.g. the store was mutated concurrently, the package blob was deleted, or verification failed and returned None.
Common situations: A concurrent capsule uninstall/prune racing the contracts refresh; corrupted or manually pruned capsule store directories; disk-full/interrupted write leaving a registry entry without its package; differing store versions across replicas.
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
- shutdown stage gateway.startup_identity: startup generation
- projected file changed while read: {}
- corpus input changed while its baseline snapshot was capture
- mountpoint was concurrently registered: {}
- capsule {id} disappeared during introspection
AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09).
Data as JSON: /api/errors/02a9c4586c9606bc.
Report an issue: GitHub.