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.

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.

Appendix: 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)