diem/diem · error

Previous epoch ending LedgerInfo is not the one expected. My

Error message

Previous epoch ending LedgerInfo is not the one expected. My first epoch: {}, previous LedgerInfo next_block_epoch: {}

What it means

The restore verifies continuity: the `next_block_epoch` of the previously restored epoch-ending LedgerInfo must equal the `first_epoch` in the backup manifest. If the epoch you are restoring from doesn't continue exactly where the local chain ends, this error fires with both epochs printed. It guards against restoring a backup that doesn't link to the existing database state.

Source

Thrown at storage/backup/backup-cli/src/backup_types/epoch_ending/restore.rs:219

    }
}

impl PreheatedEpochEndingRestore {
    async fn run_impl(
        self,
        previous_epoch_ending_ledger_info: Option<&LedgerInfo>,
    ) -> Result<Vec<LedgerInfo>> {
        let preheat_data = self
            .preheat_result
            .map_err(|e| anyhow!("Preheat failed: {}", e))?;

        let first_li = preheat_data
            .ledger_infos
            .first()
            .expect("Epoch ending backup can't be empty.");

        if let Some(li) = previous_epoch_ending_ledger_info {
            ensure!(
                li.next_block_epoch() == preheat_data.manifest.first_epoch,
                "Previous epoch ending LedgerInfo is not the one expected. \
                My first epoch: {}, previous LedgerInfo next_block_epoch: {}",
                preheat_data.manifest.first_epoch,
                li.next_block_epoch(),
            );
            // Waypoint has been verified in preheat if it's trusted, otherwise try to check
            // the signatures.
            if self
                .controller
                .trusted_waypoints
                .get(&first_li.ledger_info().version())
                .is_none()
            {
                li.next_epoch_state()
                    .ok_or_else(|| {
                        anyhow!("Previous epoch ending LedgerInfo doesn't end an epoch")
                    })?

View on GitHub (pinned to fc4714a8ea)

Solutions

  1. Check the two printed epochs: the backup's first epoch must be exactly the previous LedgerInfo's next_block_epoch.
  2. Download and restore the missing/in-between epoch-ending backup so the chain is continuous.
  3. Confirm you are targeting the correct backup manifest handle for the epoch range that follows your current DB state.
  4. If the DB state is wrong/branchy, re-plan the restore from a known-good waypoint using the same chain's backups.

Example fix

// before: assuming any epoch-ending backup continues the chain
controller.preheat().await?.run(Some(&prev_li)).await?;
// after: check continuity first
let manifest = client.get_backup(backup_handle).await?;
assert_eq!(
    prev_li.next_block_epoch(),
    manifest.first_epoch,
    "backup must start at epoch {}",
    prev_li.next_block_epoch()
);
controller.preheat().await?.run(Some(&prev_li)).await?;
Defensive patterns

Strategy: validation

Validate before calling

// before calling run, check epoch continuity
let manifest: EpochEndingBackup = client.get_backup(manifest_handle).await?;
if let Some(prev) = &prev_li {
    ensure!(
        prev.next_block_epoch() == manifest.first_epoch,
        "need backup starting at epoch {}, got {}",
        prev.next_block_epoch(),
        manifest.first_epoch
    );
}

Try / catch

match restore.run(Some(&prev_li)).await {
    Err(e) if e.to_string().contains("not the one expected") => {
        // fetch the correct epoch-ending backup for prev_li.next_block_epoch()
        Err(anyhow!("wrong backup selected: {}", e))
    }
    other => other,
}

Prevention

When it happens

Trigger: `run` called with `Some(&li)` where `li.next_block_epoch() != preheat_data.manifest.first_epoch` — e.g. wrong backup manifest handle selected, or the previous epoch-ending restore was skipped/overlapped.

Common situations: Restoring epoch-ending backups out of order or skipping one epoch; pointing the restore at a manifest from the wrong epoch range; mixing backups from different chains (e.g. testnet file into a mainnet DB); a previous restore that failed halfway leaving the DB at an unexpected epoch.

Related errors


AI-assisted analysis of diem/diem@fc4714a8ea (2026-09-04). Data as JSON: /api/errors/8284c32c57e3cf41. Report an issue: GitHub.