astrid-runtime/astrid · error
legacy log receipt identity mismatch
Error message
legacy log receipt identity mismatch: {} What it means
The legacy log import receipt on disk does not match the expected schema version or does not belong to the requested uid. The kernel requires every receipt to carry the current RECEIPT_SCHEMA and the same uid it was written for before it can be used as a destination proof. This prevents an old-format or misfiled receipt from being trusted during migration verification.
Solutions
- Delete or move aside the stale receipt so it is regenerated (an absent receipt is handled as "absent")
- Re-run the legacy log migration so a fresh receipt with the current schema and uid is written
- If upgrading, run any provided migration/upgrade command that rewrites receipts before verification
- Do not hand-edit or copy receipt files between uid paths
Defensive patterns
Strategy: validation
Validate before calling
// before relying on a receipt, check its schema/uid yourself
let receipt: serde_json::Value = serde_json::from_slice(&bytes)?;
if receipt["schema"] != EXPECTED_SCHEMA || receipt["uid"] != uid {
// stale or foreign receipt: treat as absent and let it regenerate
std::fs::remove_file(&path)?;
} Type guard
fn is_current_receipt(r: &LogReceipt, uid: &str) -> bool {
r.schema == RECEIPT_SCHEMA && r.uid == uid
} Prevention
- Never copy receipt files between uid paths or homes
- Run the app's upgrade/migration command after version bumps before verification
- Treat receipts as opaque kernel-managed files
When it happens
Trigger: `legacy_log_destination_proof` reads the receipt at `receipt_path(home, uid)` and finds `receipt.schema != RECEIPT_SCHEMA` or `receipt.uid != uid`. Triggered by receipts written by an older kernel version, a receipt copied/renamed to another uid's path, or a hand-edited receipt.
Common situations: Upgrading the app across a schema-version bump while old receipts remain on disk; manually copying home directories between accounts/uids; restoring a partial backup where receipts and logs diverged.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
- layout migration receipt does not match its intent or…
- layout-two home contains legacy state without a completion…
- legacy capsule authority identity differs for
- legacy capsule authority receipt disappeared
- legacy capsule authority verification produced no receipt
AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09).
Data as JSON: /api/errors/df38fdc189ab408e.
Report an issue: GitHub.
Appendix: source
Thrown at crates/astrid-kernel/src/principal_log_migration.rs:89
/// The migration verifies every destination byte before publishing this
/// receipt. Runtime logs are appendable operational state, so later proof
/// checks bind the immutable receipt rather than re-hashing the live log tree.
///
/// # Errors
///
/// Returns an error when the receipt exists but is malformed or belongs to a
/// different UID.
pub(crate) fn legacy_log_destination_proof(
home: &AstridHome,
uid: PrincipalUid,
) -> io::Result<String> {
let path = receipt_path(home, uid);
let Some(bytes) = read_receipt_bytes(&path)? else {
return Ok("absent".to_owned());
};
let receipt: LogReceipt = decode_receipt(&bytes, &path)?;
if receipt.schema != RECEIPT_SCHEMA || receipt.uid != uid {
return Err(io::Error::new(
io::ErrorKind::InvalidData,
format!("legacy log receipt identity mismatch: {}", path.display()),
));
}
Ok(format!("blake3:{}", blake3::hash(&bytes).to_hex()))
}
fn migrate_one(
home: &AstridHome,
alias: &PrincipalId,
uid: PrincipalUid,
source: &Path,
) -> io::Result<()> {
let receipt_path = receipt_path(home, uid);
if let Some(bytes) = read_receipt_bytes(&receipt_path)? {
let receipt: LogReceipt = decode_receipt(&bytes, &receipt_path)?;
if receipt.schema != RECEIPT_SCHEMA || receipt.uid != uid || receipt.alias != *alias {
return Err(conflict(View on GitHub (pinned to affd8760f4)