astrid-runtime/astrid · critical

capsule content changed after authority decision (approved {

Error message

capsule content changed after authority decision (approved {}, found {})

What it means

`authority_for_install_source` re-verifies the capsule source directory and compares the freshly computed `content_digest` against the content digest recorded in the previously approved authority decision. This error is thrown when the capsule's bytes changed between the operator's approval and the actual install, preventing a decision made for one artifact from being silently applied to different content.

Source

Thrown at crates/astrid-capsule-install/src/authority.rs:922

        capability_expansions,
        manifest_digest: artifact.manifest_digest,
        requested_capabilities: manifest.capabilities,
    })
}

pub(crate) fn authority_for_install_source(
    source_dir: &Path,
    manifest: &CapsuleManifest,
    approved: Option<InstalledAuthority>,
) -> anyhow::Result<InstalledAuthority> {
    let verification = artifact::verify_directory(source_dir)?;
    let content_digest = verification.content_digest().to_string();
    let manifest_digest = digest_manifest(&std::fs::read(source_dir.join("Capsule.toml"))?);
    let (signer, signature) = verification_provenance(&verification);

    if let Some(approved) = approved {
        if approved.content_digest != content_digest {
            bail!(
                "capsule content changed after authority decision (approved {}, found {})",
                approved.content_digest,
                content_digest
            );
        }
        if approved.signer != signer || approved.signature != signature {
            bail!("capsule provenance changed after authority decision");
        }
        if approved.capsule_id != manifest.package.name
            || approved.version != manifest.package.version
        {
            bail!("capsule identity or version changed after authority decision");
        }
        if approved.manifest_digest != manifest_digest {
            bail!("capsule manifest changed after authority decision");
        }
        if approved.approved_capabilities != manifest.capabilities {
            bail!("capsule capabilities changed after authority decision");

View on GitHub (pinned to affd8760f4)

Solutions

  1. Re-run the authority review/decision on the current source directory so a receipt matching the new content_digest is issued
  2. Restore the source directory to the exact reviewed content (e.g. git checkout the reviewed commit) and retry the install
  3. If the change is intentional and reviewed, redo the approval flow rather than bypassing the digest check

Example fix

// before
bail!("capsule content changed after authority decision (approved {}, found {})", approved.content_digest, content_digest);
// after: refresh the decision for current content
// let authority = decision::approve(source_dir)?;   // re-approve
// install_from_local_path_internal(source_dir, Some(authority))
Defensive patterns

Strategy: validation

Validate before calling

// Compute the current content digest and compare with the approved decision before installing
let current = artifact::verify_directory(source_dir)?.content_digest().to_string();
assert_eq!(approved.content_digest, current, "content changed since approval; re-approve");

Type guard

fn digest_unchanged(approved: &InstalledAuthority, current: &str) -> bool {
    approved.content_digest == current
}

Try / catch

match authority_for_install_source(source_dir, &manifest, Some(approved)) {
    Ok(a) => install(a),
    Err(e) if e.to_string().contains("changed after authority decision") => reapprove_and_retry(),
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Calling `install_from_local_path_internal` with an `approved: Option<InstalledAuthority>` whose `content_digest` differs from the digest of the source directory at install time — i.e. files in the source dir were added, removed, or edited after the authority decision was recorded.

Common situations: Editing capsule source or rebuilding the WASM artifact after approving the install; a build tool regenerating outputs in the source directory between approval and install; running install from a different (dirty) checkout than the one reviewed.

Understand the failure class

Background: Checksum mismatch errors: "checksum verification failed", "digest mismatch", "expected vs actual checksum" — what they mean and how to fix them — this error's family across 41 libraries.

Related errors


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