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

Contract utxo should not exist

Error message

Contract utxo should not exist

What it means

Duplicate guard for ContractsLatestUtxo during on-chain genesis import: replace(&contract_id, &entry.value) returned Some, meaning this contract id already has a latest-utxo record — either another entry with the same contract id earlier in the same genesis batch, or an existing record in the database.

Source

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

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>,
) -> anyhow::Result<()> {
    let payload = entry.value.as_ref();
    let blob_id = entry.key;

    // insert blob payload
    if transaction
        .storage::<BlobData>()
        .replace(&blob_id, payload)?
        .is_some()
    {

View on GitHub (pinned to b9d4d170da)

Solutions

  1. Dedupe contracts_latest_utxo entries by contract id in the genesis state and re-import.
  2. Wipe the on-chain db directory and retry so the importer starts from empty storage.
  3. Regenerate the snapshot with tooling that guarantees a single latest-utxo record per contract id.

Example fix

// before: two entries with the same key 0xdead...
"contracts_latest_utxo": [
  { "key": "0xdead...", "value": { "utxo_id": "0x01", "tx_pointer": { "block_height": 0, "tx_index": 0 } } },
  { "key": "0xdead...", "value": { "utxo_id": "0x02", "tx_pointer": { "block_height": 0, "tx_index": 1 } } }
]

// after: keep only one entry per contract id
"contracts_latest_utxo": [
  { "key": "0xdead...", "value": { "utxo_id": "0x02", "tx_pointer": { "block_height": 0, "tx_index": 1 } } }
]
Defensive patterns

Strategy: validation

Validate before calling

fn validate_contract_utxo_uniqueness(
    entries: &[TableEntry<ContractsLatestUtxo>],
) -> Result<(), String> {
    let mut seen = std::collections::HashSet::new();
    for e in entries {
        if !seen.insert(e.key) {
            return Err(format!("duplicate ContractsLatestUtxo entry for contract {}", e.key));
        }
    }
    Ok(())
}

Try / catch

match importer.run().await {
    Err(e) if e.to_string().contains("Contract utxo should not exist") => {
        // dedupe contracts_latest_utxo by contract id, wipe db, re-import
    }
    rest => rest,
}

Prevention

When it happens

Trigger: The genesis state lists the same contract id twice under contracts_latest_utxo, or the importer runs against a database that already contains records for those contracts.

Common situations: Merging two state snapshots that both contain the same contracts; snapshot generation bugs emitting multiple latest-utxo records per contract; restarting genesis import into a populated db directory.

Related errors


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