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

  1. Diff the current receipt against component.destination_proof in the ledger to see what changed.
  2. Restore the original receipt from backup, or delete both ledger and receipts for a full clean re-migration.
  3. 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

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


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