{"record":{"id":"8284c32c57e3cf41","repo":"diem/diem","slug":"previous-epoch-ending-ledgerinfo-is-not-the-one-ex","errorCode":null,"errorMessage":"Previous epoch ending LedgerInfo is not the one expected. My first epoch: {}, previous LedgerInfo next_block_epoch: {}","messagePattern":"Previous epoch ending LedgerInfo is not the one expected\\. My first epoch: (.+?), previous LedgerInfo next_block_epoch: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"storage/backup/backup-cli/src/backup_types/epoch_ending/restore.rs","lineNumber":219,"sourceCode":"    }\n}\n\nimpl PreheatedEpochEndingRestore {\n    async fn run_impl(\n        self,\n        previous_epoch_ending_ledger_info: Option<&LedgerInfo>,\n    ) -> Result<Vec<LedgerInfo>> {\n        let preheat_data = self\n            .preheat_result\n            .map_err(|e| anyhow!(\"Preheat failed: {}\", e))?;\n\n        let first_li = preheat_data\n            .ledger_infos\n            .first()\n            .expect(\"Epoch ending backup can't be empty.\");\n\n        if let Some(li) = previous_epoch_ending_ledger_info {\n            ensure!(\n                li.next_block_epoch() == preheat_data.manifest.first_epoch,\n                \"Previous epoch ending LedgerInfo is not the one expected. \\\n                My first epoch: {}, previous LedgerInfo next_block_epoch: {}\",\n                preheat_data.manifest.first_epoch,\n                li.next_block_epoch(),\n            );\n            // Waypoint has been verified in preheat if it's trusted, otherwise try to check\n            // the signatures.\n            if self\n                .controller\n                .trusted_waypoints\n                .get(&first_li.ledger_info().version())\n                .is_none()\n            {\n                li.next_epoch_state()\n                    .ok_or_else(|| {\n                        anyhow!(\"Previous epoch ending LedgerInfo doesn't end an epoch\")\n                    })?","sourceCodeStart":201,"sourceCodeEnd":237,"githubUrl":"https://github.com/diem/diem/blob/fc4714a8ea273b6efe8b13dbce72ea60aad9a16c/storage/backup/backup-cli/src/backup_types/epoch_ending/restore.rs#L201-L237","documentation":"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.","triggerScenarios":"`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.","commonSituations":"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.","solutions":["Check the two printed epochs: the backup's first epoch must be exactly the previous LedgerInfo's next_block_epoch.","Download and restore the missing/in-between epoch-ending backup so the chain is continuous.","Confirm you are targeting the correct backup manifest handle for the epoch range that follows your current DB state.","If the DB state is wrong/branchy, re-plan the restore from a known-good waypoint using the same chain's backups."],"exampleFix":"// before: assuming any epoch-ending backup continues the chain\ncontroller.preheat().await?.run(Some(&prev_li)).await?;\n// after: check continuity first\nlet manifest = client.get_backup(backup_handle).await?;\nassert_eq!(\n    prev_li.next_block_epoch(),\n    manifest.first_epoch,\n    \"backup must start at epoch {}\",\n    prev_li.next_block_epoch()\n);\ncontroller.preheat().await?.run(Some(&prev_li)).await?;","handlingStrategy":"validation","validationCode":"// before calling run, check epoch continuity\nlet manifest: EpochEndingBackup = client.get_backup(manifest_handle).await?;\nif let Some(prev) = &prev_li {\n    ensure!(\n        prev.next_block_epoch() == manifest.first_epoch,\n        \"need backup starting at epoch {}, got {}\",\n        prev.next_block_epoch(),\n        manifest.first_epoch\n    );\n}","typeGuard":null,"tryCatchPattern":"match restore.run(Some(&prev_li)).await {\n    Err(e) if e.to_string().contains(\"not the one expected\") => {\n        // fetch the correct epoch-ending backup for prev_li.next_block_epoch()\n        Err(anyhow!(\"wrong backup selected: {}\", e))\n    }\n    other => other,\n}","preventionTips":["Always restore epoch-ending backups in strict epoch order, one per epoch, with no gaps.","Derive the manifest handle programmatically from the current DB epoch rather than hardcoding it.","Never mix backups from different chains/environments (mainnet vs testnet).","Record and check the last restored epoch in a local checkpoint file between restore runs."],"tags":["backup-restore","epoch-mismatch","continuity","waypoint"],"backgroundTag":"epoch-continuity-mismatch","analyzedSha":"fc4714a8ea273b6efe8b13dbce72ea60aad9a16c","analyzedAt":"2026-09-04T21:07:05.890Z","contentChangedAt":"2026-09-04T21:07:05.890Z","schemaVersion":2},"datasetVersion":"2026-09-12T02:17:10.037Z"}