FuelLabs/fuel-core · error

relayer database height({relayer_db_height}) is less than ta

Error message

relayer database height({relayer_db_height}) is less than target height({target_da_height})

What it means

rollback_relayer_to rewinds the relayer (DA) database to a target DA block height. Its height is Optional, but if Some(height) is strictly below target_da_height the rollback aborts: the relayer DB would need to move forward, which rollback never does. The relayer DB must first catch up to (or past) the target before it can be trimmed back.

Source

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

        target_da_height: DaBlockHeight,
        shutdown_listener: &mut S,
    ) -> anyhow::Result<()>
    where
        S: ShutdownListener,
    {
        while !shutdown_listener.is_cancelled() {
            let relayer_db_height = self.relayer().latest_height_from_metadata()?;
            let relayer_db_rolled_back =
                is_equal_or_none(relayer_db_height, target_da_height);

            if relayer_db_rolled_back {
                break;
            }

            if let Some(relayer_db_height) = relayer_db_height
                && relayer_db_height < target_da_height
            {
                return Err(anyhow::anyhow!(
                    "relayer database height({relayer_db_height}) \
                    is less than target height({target_da_height})"
                ));
            }

            if let Some(relayer_db_height) = relayer_db_height
                && relayer_db_height > target_da_height
            {
                self.relayer().rollback_last_block()?;
            }
        }

        if shutdown_listener.is_cancelled() {
            return Err(anyhow::anyhow!(
                "Stop the rollback due to shutdown signal received"
            ));
        }

View on GitHub (pinned to b9d4d170da)

Solutions

  1. Let the relayer sync forward from the DA layer until its height >= target_da_height, then retry the rollback.
  2. Derive target_da_height from the relayer DB's own current height rather than from chain state.
  3. If relayer history is disposable, wipe the relayer DB and let it re-sync.
Defensive patterns

Strategy: validation

Validate before calling

if let Some(relayer_height) = db.relayer().latest_height_from_metadata()? {
    if target_da_height > relayer_height {
        anyhow::bail!("relayer at {} is behind target {}; sync the relayer first", relayer_height, target_da_height);
    }
}
db.rollback_relayer_to(target_da_height, &mut shutdown)?;

Try / catch

match db.rollback_relayer_to(target_da_height, &mut shutdown) {
    Ok(()) => Ok(()),
    Err(e) if e.to_string().contains("relayer database height") => {
        // relayer must move forward first: this is a sync problem, not a rollback problem
        anyhow::bail!("sync relayer to >= {} before rollback: {}", target_da_height, e)
    }
    Err(e) => Err(e),
}

Prevention

When it happens

Trigger: Calling rollback_relayer_to with a DA height above the relayer database's recorded height — relayer lagging behind DA layer, or a target computed from chain/consensus metadata that the relayer DB has not reached.

Common situations: Relayer temporarily disabled or falling behind the DA layer; restoring the relayer DB from an old snapshot; passing an on-chain-derived DA height without validating relayer progress.

Related errors


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