FuelLabs/fuel-core · error · anyhow::Error

coin tx_pointer height ({coin_height}) cannot be greater tha

Error message

coin tx_pointer height ({coin_height}) cannot be greater than genesis block ({height})

What it means

During genesis snapshot import, each coin's tx_pointer.block_height() must be <= the genesis block height; a pointer above genesis references blocks that do not exist yet, so import_db fails fast rather than storing a forward-pointing coin. This validates snapshot integrity at import time.

Source

Thrown at crates/fuel-core/src/service/genesis/importer/on_chain.rs:233

    transaction: &mut StorageTransaction<&mut GenesisDatabase>,
    coin: &TableEntry<Coins>,
    height: BlockHeight,
) -> anyhow::Result<()> {
    let utxo_id = coin.key;

    let compressed_coin = Coin {
        utxo_id,
        owner: *coin.value.owner(),
        amount: *coin.value.amount(),
        asset_id: *coin.value.asset_id(),
        tx_pointer: *coin.value.tx_pointer(),
    }
    .compress();

    // ensure coin can't point to blocks in the future
    let coin_height = coin.value.tx_pointer().block_height();
    if coin_height > height {
        return Err(anyhow!(
            "coin tx_pointer height ({coin_height}) cannot be greater than genesis block ({height})"
        ));
    }

    if transaction
        .storage::<Coins>()
        .replace(&utxo_id, &compressed_coin)?
        .is_some()
    {
        return Err(anyhow!("Coin should not exist"));
    }

    Ok(())
}

fn init_contract_latest_utxo(
    transaction: &mut StorageTransaction<&mut GenesisDatabase>,
    entry: &TableEntry<ContractsLatestUtxo>,

View on GitHub (pinned to b9d4d170da)

Solutions

  1. Regenerate the snapshot with every coin's tx_pointer height <= genesis height (zero or genesis height).
  2. Pre-validate the snapshot's coins before import (see validation snippet).
  3. For migrating live chains, use the proper migration path instead of a genesis snapshot.
Defensive patterns

Strategy: validation

Validate before calling

// Pre-validate the snapshot before import: every coin's tx_pointer height
// must be <= genesis height.
fn snapshot_coins_valid(
    coins: impl Iterator<Item = (UtxoId, CoinConfig)>,
    genesis_height: u32,
) -> Result<(), String> {
    for (utxo_id, coin) in coins {
        let h = coin.tx_pointer.block_height();
        if h > genesis_height {
            return Err(format!(
                "coin {utxo_id} tx_pointer height {h} > genesis {genesis_height}"
            ));
        }
    }
    Ok(())
}

Try / catch

if let Err(e) = import_result {
    if e.to_string().contains("cannot be greater than genesis block") {
        return Err(anyhow!("snapshot invalid: fix coin tx_pointer heights and regenerate"));
    }
    return Err(e);
}

Prevention

When it happens

Trigger: Importing a snapshot (genesis chain config / snapshot reader) that contains a coin whose tx_pointer height exceeds the chain's genesis height — e.g. state converted from a live chain without resetting coin pointers.

Common situations: Converting existing chain state into a genesis snapshot without zeroing tx_pointers; hand-edited snapshots; snapshots generated by tooling that copies original block heights.

Related errors


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