astrid-runtime/astrid · error

legacy capsule authority receipt changed before retirement

Error message

legacy capsule authority receipt changed before retirement: {}

What it means

Fired by retire_legacy_authority_receipt when the receipt bytes read from disk no longer match the published bytes that were verified earlier. The receipt mutated between verification and retirement, so deletion would discard changed content.

Solutions

  1. Investigate what modified the receipt (concurrent migration, tampering)
  2. Re-run the migration after the writer is stopped
  3. Restore the expected receipt or reinstall the capsule
Defensive patterns

Strategy: retry

When it happens

Trigger: Thrown at crates/astrid-capsule-install/src/authority.rs:273 when the library encounters an invalid state.

Common situations: See trigger scenarios.


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

Appendix: source

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

            paths.active.display()
        )
    })?;
    if metadata.file_type().is_symlink() || !metadata.is_file() {
        bail!(
            "legacy capsule authority receipt is not a regular file: {}",
            paths.active.display()
        );
    }
    astrid_core::platform_fs::verify_no_redirects(&paths.active).with_context(|| {
        format!(
            "verify legacy capsule authority receipt {}",
            paths.active.display()
        )
    })?;
    let actual = std::fs::read(&paths.active)
        .with_context(|| format!("read legacy capsule authority {}", paths.active.display()))?;
    if actual != expected_bytes {
        bail!(
            "legacy capsule authority receipt changed before retirement: {}",
            paths.active.display()
        );
    }
    // Re-stat and re-read immediately before unlinking.  This does not turn a
    // host filesystem into a transaction, but closes the ordinary mutation
    // window exercised by migration/recovery and preserves a changed source.
    let final_metadata = std::fs::symlink_metadata(&paths.active)?;
    if final_metadata.file_type().is_symlink()
        || !final_metadata.is_file()
        || final_metadata.len() != actual.len() as u64
        || std::fs::read(&paths.active)?.as_slice() != expected_bytes
    {
        bail!(
            "legacy capsule authority receipt changed during retirement: {}",
            paths.active.display()
        );
    }

View on GitHub (pinned to affd8760f4)