astrid-runtime/astrid · error
destination receipt changed for migration component {}
Error message
destination receipt changed for migration component {} What it means
When revalidating an existing layout, each immutable component's currently stored proof is compared against the destination_proof expected from the ledger. If they differ, this error is thrown: the recorded receipt for that component changed since migration, which breaks the immutability guarantee, so resume fails closed.
Source
Thrown at crates/astrid-kernel/src/legacy_migration_barrier/ledger.rs:415
}
for component in &existing.components {
if mutable_component(&component.name) {
continue;
}
if let Some(uid) = principal_component_uid(&component.name)
&& !principal_homes.contains(&uid)
{
return Err(io::Error::new(
io::ErrorKind::InvalidData,
format!(
"principal migration component has no ordinary-home receipt: {}",
component.name
),
));
}
if let Some(current) = proofs.get(&component.name) {
if current != &component.destination_proof {
return Err(io::Error::new(
io::ErrorKind::InvalidData,
format!(
"destination receipt changed for migration component {}",
component.name
),
));
}
continue;
}
if component.name.starts_with("system:") {
return Err(io::Error::new(
io::ErrorKind::InvalidData,
format!(
"required system migration receipt is missing: {}",
component.name
),
));
}View on GitHub (pinned to affd8760f4)
Solutions
- Diff the current receipt against component.destination_proof in the ledger to see what changed.
- Restore the original receipt from backup, or delete both ledger and receipts for a full clean re-migration.
- Never regenerate receipts by hand; use the migration entry points so proofs and ledger stay consistent.
Example fix
// before: receipt file overwritten externally $ cp <backup>/migrations/<component>.json <migrations-dir>/<component>.json // after (if no backup): clean re-migration $ rm -r <migrations-dir> && astrid migrate
Defensive patterns
Strategy: validation
Validate before calling
let stored = std::fs::read_to_string(proof_path)?;
if stored != component.destination_proof {
eprintln!("receipt drift detected for {}; restore from backup", component.name);
} Try / catch
match resume_existing_layout(...) {
Err(e) if e.to_string().contains("destination receipt changed") => {
eprintln!("receipt was modified externally; restore backup or full re-migrate");
}
r => r?,
} Prevention
- Make migrations_dir read-only to non-root/non-user after migration.
- Treat any receipt drift as tampering and investigate before re-migrating.
- Regenerate ledger and receipts together; never rewrite one side only.
When it happens
Trigger: validate_existing_proofs (via resume_existing_layout or existing_layout_requires_receipts_for_live_immutable_components) reads proofs from the ledger and finds a mismatch with component.destination_proof — e.g. the receipt file on disk was overwritten, or component metadata changed after the ledger was written.
Common situations: Someone edited or re-wrote a receipt in migrations_dir; the ledger and receipts got out of sync after a partial restore or an interrupted re-migration; running a newer library version that recomputed proofs with different content.
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
- invalid capsule authority migration receipt: {}
- principal migration ledger is missing the ordinary-home comp
- principal migration component has no ordinary-home receipt:
- required system migration receipt is missing: {}
- live principal migration receipt is missing: {}
AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09).
Data as JSON: /api/errors/b8b4e201d84d6117.
Report an issue: GitHub.