astrid-runtime/astrid · error
gateway revocation migration receipt conflicts
Error message
gateway revocation migration receipt conflicts
What it means
Receipt conflict in migrate_legacy_file: a migration receipt already exists in the control KV but its encoded bytes differ from the receipt computed for this legacy file — a different digest or count, meaning the file changed after a previous migration or two sources disagree.
Solutions
- Compare the existing receipt's digest with the current file's blake3 digest
- If the file was edited after migration, restore the original or re-derive entries manually
- If the existing receipt is stale/incorrect, remove it deliberately and re-run migration
Defensive patterns
Strategy: validation
When it happens
Trigger: Thrown at crates/astrid-gateway/src/revocations.rs:417 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/4d6d526344a6b543.
Report an issue: GitHub.
Appendix: source
Thrown at crates/astrid-gateway/src/revocations.rs:417
if durable < *epoch {
anyhow::bail!(
"principal revocation {principal} read back epoch {durable}, expected at least {epoch}"
);
}
}
let receipt = LegacyMigrationReceipt {
schema: 1,
digest,
principal_count: entries.len(),
};
let encoded = serde_json::to_vec(&receipt).context("encode revocation migration receipt")?;
let existing = store
.get(REVOCATION_NAMESPACE, MIGRATION_RECEIPT_KEY)
.await
.map_err(|error| anyhow::anyhow!("read revocation migration receipt: {error}"))?;
if let Some(existing) = existing {
if existing != encoded {
anyhow::bail!("gateway revocation migration receipt conflicts");
}
} else if !store
.compare_and_swap(REVOCATION_NAMESPACE, MIGRATION_RECEIPT_KEY, None, encoded)
.await
.map_err(|error| anyhow::anyhow!("write revocation migration receipt: {error}"))?
{
anyhow::bail!("gateway revocation migration receipt raced; retry startup");
}
let _ = load_from_store(store).await?;
match std::fs::remove_file(&path) {
Ok(()) => {},
Err(error) if error.kind() == std::io::ErrorKind::NotFound => {},
Err(error) => return Err(anyhow::anyhow!("retire {}: {error}", path.display())),
}
Ok(true)
}
/// Spawn the audit-event watcher. Subscribes to the kernel's auditView on GitHub (pinned to affd8760f4)