astrid-runtime/astrid · error

capsule {} disappeared during durable scan

Error message

capsule {} disappeared during durable scan

What it means

scan_durable_capsules lists a principal's capsules from the durable registry and then fetches a full snapshot for each summary. If the snapshot lookup returns None for a summary that the same registry just listed, the registry is internally inconsistent (the entry vanished between list and get_snapshot), and the scan bails with this message rather than silently dropping the capsule.

Source

Thrown at crates/astrid-capsule-install/src/meta.rs:158

    pub meta: Option<CapsuleMeta>,
    /// Where this capsule was found.
    pub location: CapsuleLocation,
}

/// Enumerate authoritative packages for one owner-root content projection.
///
/// This is the steady-state discovery API. It never scans native home or
/// workspace capsule directories; those paths are migration/cache inputs only.
pub fn scan_durable_capsules(
    store: &RuntimePrincipalStore,
    owner: &StateOwner,
    location: CapsuleLocation,
) -> anyhow::Result<Vec<InstalledCapsule>> {
    let registry = store.capsules();
    let mut capsules = Vec::new();
    for summary in registry.list(owner)? {
        let Some(snapshot) = registry.get_snapshot(owner, summary.id())? else {
            anyhow::bail!("capsule {} disappeared during durable scan", summary.id());
        };
        let meta = serde_json::from_slice(&snapshot.package().metadata)
            .with_context(|| format!("decode durable metadata for capsule {}", summary.id()))?;
        capsules.push(InstalledCapsule {
            name: summary.id().to_owned(),
            meta: Some(meta),
            location,
        });
    }
    capsules.sort_by(|left, right| left.name.cmp(&right.name));
    Ok(capsules)
}

/// Scan user-level and workspace capsule directories, returning all installed
/// capsules sorted alphabetically by name.
pub fn scan_installed_capsules() -> anyhow::Result<Vec<InstalledCapsule>> {
    scan_installed_capsules_with_layout(&WorkspaceLayout::default())
}

View on GitHub (pinned to affd8760f4)

Solutions

  1. Re-run the scan; a transient concurrent delete may succeed on the second pass
  2. Stop concurrent writers (other capsule installs/removes) during the scan
  3. Inspect the principal store for orphaned summary entries and repair/remove them
  4. If caused by external cleanup, restore capsule snapshots from backup or reinstall the capsule
Defensive patterns

Strategy: retry

Try / catch

let capsules = loop {
    match scan_durable_capsules(&store, owner, location).await {
        Ok(c) => break c,
        Err(e) if e.to_string().contains("disappeared during durable scan") && retries < 3 => { retries += 1; continue; }
        Err(e) => return Err(e),
    }
};

Prevention

When it happens

Trigger: Concurrent deletion of a capsule (e.g. another process/thread calling remove on the RuntimePrincipalStore) between registry.list(owner) and registry.get_snapshot(owner, id); a corrupted or pruned store where snapshots were removed but summary index entries remain.

Common situations: Two tools managing capsules on the same principal concurrently; a crash or manual store cleanup that removed snapshot data but left summaries; filesystem-level deletion under the store while a scan runs.

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


AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09). Data as JSON: /api/errors/9839c8cb076e2f96. Report an issue: GitHub.