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

contract tx_pointer cannot be greater than genesis block

Error message

contract tx_pointer cannot be greater than genesis block

What it means

Thrown by init_contract_latest_utxo during on-chain genesis import. Each ContractsLatestUtxo entry records the utxo that last created or updated a contract, and its tx_pointer must reference a block at or below the height of the genesis block being imported. When entry.value.tx_pointer().block_height() exceeds that height, the contract would point at a block that does not exist yet at genesis, so the import is rejected.

Source

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

        .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>,
    height: BlockHeight,
) -> anyhow::Result<()> {
    let contract_id = entry.key;

    if entry.value.tx_pointer().block_height() > height {
        return Err(anyhow!(
            "contract tx_pointer cannot be greater than genesis block"
        ));
    }

    if transaction
        .storage::<ContractsLatestUtxo>()
        .replace(&contract_id, &entry.value)?
        .is_some()
    {
        return Err(anyhow!("Contract utxo should not exist"));
    }

    Ok(())
}

fn init_blob_payload(
    transaction: &mut StorageTransaction<&mut GenesisDatabase>,
    entry: &TableEntry<BlobData>,

View on GitHub (pinned to b9d4d170da)

Solutions

  1. Raise the genesis block height in the chain config so it is greater than or equal to the maximum tx_pointer block height across all ContractsLatestUtxo entries.
  2. Or rewrite the offending entries' tx_pointer block heights to values at or below the genesis height (regenerating the snapshot is safer than hand edits).
  3. Re-export the snapshot at the exact height you declare as genesis so heights stay consistent.

Example fix

// before: chain config declares genesis height 42,
// but a contracts_latest_utxo entry has tx_pointer.block_height = 50
{ "tx_pointer": { "block_height": 50, "tx_index": 0 } }

// after: make the genesis height cover the pointer
// chain_config: "height": 50
// (or set the entry's tx_pointer.block_height to <= 42)
Defensive patterns

Strategy: validation

Validate before calling

fn validate_contract_utxo_heights(
    entries: &[TableEntry<ContractsLatestUtxo>],
    genesis_height: u32,
) -> Result<(), String> {
    for e in entries {
        if e.value.tx_pointer().block_height().as_u32() > genesis_height {
            return Err(format!(
                "contract {} tx_pointer height {} above genesis height {}",
                e.key,
                e.value.tx_pointer().block_height(),
                genesis_height
            ));
        }
    }
    Ok(())
}

Try / catch

match importer.run().await {
    Err(e) if e.to_string().contains("tx_pointer cannot be greater than genesis") => {
        // fix snapshot heights or raise genesis height; not retryable as-is
    }
    rest => rest,
}

Prevention

When it happens

Trigger: A genesis or state snapshot whose contracts_latest_utxo entries carry tx_pointer block heights greater than the genesis block height set in the chain config — for example exporting state at height H but declaring a lower genesis height, or hand-editing tx_pointer fields.

Common situations: Building a test-network genesis from a snapshot taken at a higher height; shrinking the declared genesis height to compress the chain without rewriting snapshot pointers; snapshot tooling version changes that emit absolute instead of relative heights.

Related errors


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