astrid-runtime/astrid · error

legacy capsule {id} authority verification produced no recei

Error message

legacy capsule {id} authority verification produced no receipt

What it means

After verifying a legacy capsule's authority (`verify_installed_authority`), the migration reads back the installed authority receipt with `read_installed_authority`. If that returns `None` — no receipt file exists on disk — this error is raised. It signals an inconsistent install state: verification logically succeeded but the receipt artifact is missing, so the migration cannot construct a durable authority record.

Source

Thrown at crates/astrid-capsule-install/src/storage/migration.rs:156

        }
        let meta_bytes = fs::read(target.join("meta.json"))
            .with_context(|| format!("read legacy capsule metadata {id}"))?;
        let meta: CapsuleMeta = serde_json::from_slice(&meta_bytes)
            .with_context(|| format!("decode legacy capsule metadata {id}"))?;
        if meta.version != manifest.package.version {
            bail!("legacy capsule metadata version differs for {id}");
        }
        // Released pre-authority installs are admitted only through the
        // existing one-time verifier. It pins their exact manifest,
        // capabilities, and executable before any durable publication.
        // Relocated homes keep receipts hashed from a previous absolute
        // path; rebind a unique leftover onto this target first.
        rebind_relocated_legacy_authority_receipt(home, &target, &manifest, workspace_targets)
            .with_context(|| format!("rebind relocated leftover authority for {id}"))?;
        verify_installed_authority(home, &target, &manifest)
            .with_context(|| format!("verify legacy capsule authority {id}"))?;
        let authority = read_installed_authority(home, &target)?.ok_or_else(|| {
            anyhow::anyhow!("legacy capsule {id} authority verification produced no receipt")
        })?;
        if authority.capsule_id != id || authority.version != manifest.package.version {
            bail!("legacy capsule authority identity differs for {id}");
        }
        let source_authority_bytes = read_installed_authority_bytes(home, &target)?
            .ok_or_else(|| anyhow::anyhow!("legacy capsule {id} authority receipt disappeared"))?;
        let archive = canonical_legacy_archive(home, &target, &meta, &manifest)?;
        let verification = artifact::verify_archive_bytes(&archive)
            .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,

View on GitHub (pinned to affd8760f4)

Solutions

  1. Reinstall or re-run migration for the affected capsule so the authority receipt is regenerated during install
  2. Restore the missing receipt file from a good install of the same capsule id/version, or re-run `verify_installed_authority` followed by the receipt-persisting step in your install flow
  3. Check the relocated-receipt logic: if receipts live under path-hashed locations, ensure `rebind_relocated_legacy_authority_receipt` can find the leftover (matching capsule id and version) before migration

Example fix

// before
// receipt file manually removed during cleanup
rm ~/.capsule/installed/legacy-tools/.authority/receipt.json
migrate_native_capsules(home)?; // "legacy capsule legacy-tools authority verification produced no receipt"

// after
// reinstall so the receipt is written, then migrate
capsule install legacy-tools@1.2.3
migrate_native_capsules(home)?;
Defensive patterns

Strategy: validation

Validate before calling

fn assert_authority_receipt_present(home: &Path, target: &Path) -> anyhow::Result<()> {
    let receipt = read_installed_authority(home, target)
        .context("read installed authority")?;
    anyhow::ensure!(receipt.is_some(),
        "capsule {} has no authority receipt; reinstall before migrating",
        target.display());
    Ok(())
}
// run per legacy target before migrate_native_capsules
for target in legacy_targets { assert_authority_receipt_present(home, &target)?; }

Type guard

fn has_authority_receipt(home: &Path, target: &Path) -> bool {
    matches!(read_installed_authority(home, target), Ok(Some(_)))
}

Try / catch

match migrate_native_capsules(home) {
    Err(e) if e.to_string().contains("produced no receipt") => {
        // reinstall the named capsule to regenerate its receipt, then retry migration
    }
    Err(e) => return Err(e),
    Ok(r) => r,
}

Prevention

When it happens

Trigger: Calling `migrate_native_capsules_with_report` on a legacy capsule whose authority receipt file is absent under the install target, or whose `rebind_relocated_legacy_authority_receipt` step silently skipped because no relocated leftover matched, leaving nothing for `read_installed_authority` to find.

Common situations: Partially completed previous migration or install that wrote verification output but not the receipt; manual deletion/cleanup of receipt files inside an installed capsule; capsule directories copied between machines without their receipt sidecar files.

Understand the failure class

Background: "File not found" and ENOENT errors: why libraries can't find a file that should exist — this error's family across 50 libraries.

Related errors


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