FuelLabs/fuel-core · error · StorageError
Database doesn't have a height to rollback
Error message
Database doesn't have a height to rollback
What it means
Database::rollback_last_block reads the currently staged height (self.inner_storage().stage.height). If it is None — the database has never committed a block (not even genesis), or the stage was never populated — there is no block to roll back and the operation fails. This is the per-database primitive underlying CombinedDatabase::rollback_to.
Source
Thrown at crates/fuel-core/src/database.rs:345
columns_policy: ColumnsPolicy::Lazy,
},
)
.expect("Failed to create a temporary database")
}
}
}
impl<Description> Database<Description>
where
Description: DatabaseDescription,
{
pub fn rollback_last_block(&self) -> StorageResult<()> {
let mut lock = self.inner_storage().stage.height.lock();
let height = *lock;
let Some(height) = height else {
return Err(
anyhow::anyhow!("Database doesn't have a height to rollback").into(),
);
};
self.inner_storage().data.rollback_block_to(&height)?;
let new_height = height.rollback_height();
*lock = new_height;
tracing::info!(
"Rollback of the {} to the height {:?} was successful",
Description::name(),
new_height
);
Ok(())
}
fn latest_view_with_height(
&self,
height: Option<Description::Height>,
) -> StorageResult<IterableKeyValueView<ColumnType<Description>, Description::Height>>View on GitHub (pinned to b9d4d170da)
Solutions
- Check latest_height_from_metadata() (or the staged height) for Some before calling rollback_last_block.
- Ensure at least genesis is imported/committed before any rollback logic runs.
- Bound rollback loops so they stop at the target height instead of exhausting all blocks.
Example fix
// before
db.rollback_last_block()?;
// after
if db.latest_height_from_metadata()?.is_some() {
db.rollback_last_block()?;
} Defensive patterns
Strategy: validation
Validate before calling
match db.latest_height_from_metadata()? {
Some(_) => db.rollback_last_block()?,
None => anyhow::bail!("nothing to roll back: database has no committed height"),
} Try / catch
match db.rollback_last_block() {
Ok(()) => Ok(()),
Err(e) if e.to_string().contains("no a height to rollback") => {
// already at/below genesis — treat as done, not as failure
Ok(())
}
Err(e) => Err(e),
} Prevention
- Bound rollback loops at an explicit target height; never loop unbounded on rollback_last_block.
- Check for a committed height (genesis included) before rolling back.
- In tests, always import a block before exercising rollback paths.
When it happens
Trigger: Calling rollback_last_block on a database with no committed height: freshly created DB, DB already rolled back to/below genesis, or a DB whose stage was reset.
Common situations: Generic rollback tooling invoked on an empty chain; rollback loops that run one iteration too many (rolling back past the first block); tests calling rollback_last_block without importing a block first.
Related errors
- on-chain database doesn't have height
- off-chain database doesn't have height
- on-chain database height({on_chain_height}) is less than tar
- off-chain database height({off_chain_height}) is less than t
- gas-price database height({gas_price_chain_height}) is less
AI-assisted analysis of FuelLabs/fuel-core@b9d4d170da (2026-08-16).
Data as JSON: /api/errors/09e5a52727b1964c.
Report an issue: GitHub.