FuelLabs/fuel-core · error

off-chain database doesn't have height

Error message

off-chain database doesn't have height

What it means

Same rollback_to prelude as the on-chain check, but for the off-chain (indexes, GraphQL views) database: off_chain().latest_height_from_metadata() returned None, so the off-chain database has no recorded height and the combined rollback cannot proceed. Rollback is only defined for databases that have processed at least genesis.

Source

Thrown at crates/fuel-core/src/combined_database.rs:478

    /// Rollbacks the state of the blockchain to a specific block height.
    pub fn rollback_to<S>(
        &mut self,
        target_block_height: BlockHeight,
        shutdown_listener: &mut S,
    ) -> anyhow::Result<()>
    where
        S: ShutdownListener,
    {
        while !shutdown_listener.is_cancelled() {
            let on_chain_height = self
                .on_chain()
                .latest_height_from_metadata()?
                .ok_or(anyhow::anyhow!("on-chain database doesn't have height"))?;

            let off_chain_height = self
                .off_chain()
                .latest_height_from_metadata()?
                .ok_or(anyhow::anyhow!("off-chain database doesn't have height"))?;

            let gas_price_chain_height =
                self.gas_price().latest_height_from_metadata()?;
            let gas_price_rolled_back = is_equal_or_less_than_or_none(
                gas_price_chain_height,
                target_block_height,
            );

            let compression_db_height =
                self.compression().latest_height_from_metadata()?;
            let compression_db_rolled_back =
                is_equal_or_less_than_or_none(compression_db_height, target_block_height);

            #[cfg(feature = "rpc")]
            {
                let block_aggregation_storage_height = self
                    .block_aggregation_storage()
                    .latest_height_from_metadata()?;

View on GitHub (pinned to b9d4d170da)

Solutions

  1. Let the node run so the off-chain worker catches up and records a height, then retry the rollback.
  2. If the off-chain DB is disposable, delete it entirely and let the node rebuild it (off-chain data is derivable from on-chain state).
  3. Restore both on-chain and off-chain databases from the same consistent snapshot.
Defensive patterns

Strategy: validation

Validate before calling

let off_chain = combined_db.off_chain().latest_height_from_metadata()?;
if off_chain.is_none() {
    anyhow::bail!("off-chain DB not initialized; let the node index genesis first");
}
combined_db.rollback_to(target, &mut shutdown)?;

Try / catch

match combined_db.rollback_to(target, &mut shutdown) {
    Ok(()) => Ok(()),
    Err(e) if e.to_string().contains("off-chain database doesn't have height") => {
        // off-chain data is derivable: rebuild it, then retry
        rebuild_off_chain_db().and_then(|_| combined_db.rollback_to(target, &mut shutdown))
    }
    Err(e) => Err(e),
}

Prevention

When it happens

Trigger: rollback_to invoked when the off-chain database is empty or its metadata was never written — typically an off-chain DB created but never synced, or one whose metadata column was wiped while the on-chain DB has data.

Common situations: Mixed/partially restored database directories (on-chain restored, off-chain missing); deleting only the off-chain DB files to 'reset indexes' and then running rollback tooling; node crashed during first off-chain commit before metadata flush.

Related errors


AI-assisted analysis of FuelLabs/fuel-core@b9d4d170da (2026-08-16). Data as JSON: /api/errors/e054c495e8bf815c. Report an issue: GitHub.