astrid-runtime/astrid · error

legacy capsule authority receipt changed during retirement

Error message

legacy capsule authority receipt changed during retirement: {}

What it means

Fired by retire_legacy_authority_receipt during the final re-stat/re-read immediately before unlinking: the receipt changed in the last-moment check. The unlink is aborted so a concurrently replaced receipt is preserved rather than deleted.

Solutions

  1. Stop concurrent capsule operations, then retry retirement
  2. Investigate the competing writer (migration/recovery process)
  3. Verify receipt integrity before retrying
Defensive patterns

Strategy: retry

When it happens

Trigger: Thrown at crates/astrid-capsule-install/src/authority.rs:287 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/d2c38a2329738322. Report an issue: GitHub.

Appendix: source

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

    })?;
    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()
        );
    }
    std::fs::remove_file(&paths.active).with_context(|| {
        format!(
            "retire legacy capsule authority receipt {}",
            paths.active.display()
        )
    })?;
    sync_authority_directory(&paths.directory)
}

fn sync_authority_directory(directory: &Path) -> anyhow::Result<()> {
    #[cfg(unix)]
    {
        File::open(directory)
            .with_context(|| format!("open authority directory {}", directory.display()))?

View on GitHub (pinned to affd8760f4)