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
- Dedupe contracts_latest_utxo entries by contract id in the genesis state and re-import.
- Wipe the on-chain db directory and retry so the importer starts from empty storage.
- 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
- Dedupe every keyed table by its primary key before importing a snapshot.
- Avoid merging snapshots by concatenation; merge by key with last-write-wins tooling.
- Keep db directories empty before first import of a chain.
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
- Contract code should not exist
- Coin should not exist
- Blob should not exist
- contract tx_pointer cannot be greater than genesis block
- Message should not exist
AI-assisted analysis of FuelLabs/fuel-core@b9d4d170da (2026-08-16).
Data as JSON: /api/errors/ac0a08f766f3406e.
Report an issue: GitHub.