{"record":{"id":"adc30d901d4b0af5","repo":"FuelLabs/fuel-core","slug":"transaction-status-already-exists-for-tx","errorCode":null,"errorMessage":"Transaction status already exists for tx {}","messagePattern":"Transaction status already exists for tx (.+?)","errorType":"exception","errorClass":"StorageError","httpStatus":null,"severity":"error","filePath":"crates/fuel-core/src/graphql_api/worker_service.rs","lineNumber":461,"sourceCode":"    }\n\n    Ok(())\n}\n\nfn persist_transaction_status<T>(\n    import_result: &ImportResult,\n    asset_metadata_indexation_enabled: bool,\n    db: &mut T,\n) -> StorageResult<()>\nwhere\n    T: OffChainDatabaseTransaction,\n{\n    for TransactionExecutionStatus { id, result } in import_result.tx_status.iter() {\n        let status =\n            from_executor_to_status(&import_result.sealed_block.entity, result.clone());\n\n        if db.update_tx_status(id, status)?.is_some() {\n            return Err(anyhow::anyhow!(\n                \"Transaction status already exists for tx {}\",\n                id\n            )\n            .into());\n        }\n\n        let TransactionExecutionResult::Success { receipts, .. } = result else {\n            continue\n        };\n\n        update_receipt_based_indexation(receipts, db, asset_metadata_indexation_enabled)?;\n    }\n    Ok(())\n}\n\npub fn process_transactions<'a, I, T>(transactions: I, db: &mut T) -> StorageResult<()>\nwhere\n    I: Iterator<Item = &'a Transaction>,","sourceCodeStart":443,"sourceCodeEnd":479,"githubUrl":"https://github.com/FuelLabs/fuel-core/blob/b9d4d170da3a31c9ace5f963d633b326348e0d42/crates/fuel-core/src/graphql_api/worker_service.rs#L443-L479","documentation":"While indexing an imported block, the worker writes each transaction's status with db.update_tx_status(id, status). The method returns the previously stored status; a Some return means this tx id already had a status recorded, i.e., the block/tx is being processed twice. The worker treats duplicate status writes as an inconsistency and aborts indexing instead of silently overwriting history.","triggerScenarios":"The same TransactionExecutionStatus appears in an import result for a tx already indexed — duplicate block import, overlapping import results, or re-running the off-chain worker over an already-processed block.","commonSituations":"Re-importing a block after a crash where part of the off-chain transaction committed; worker replay without resetting the off-chain DB; bugs producing duplicate entries in import_result.tx_status; restoring off-chain DBs from mixed snapshots.","solutions":["Do not re-run the off-chain worker over blocks already indexed; resume from the off-chain DB's recorded height.","If a full re-index is intended, wipe the off-chain database first so no prior statuses exist.","Inspect import_result.tx_status for duplicate tx ids before indexing; deduplicate if the producer can emit repeats.","Verify the off-chain DB snapshot matches the on-chain DB height before restarting workers."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Skip txs already indexed before writing statuses during re-processing.\nlet ids: HashSet<_> = import_result.tx_status.iter().map(|s| s.id).collect();\nif ids.len() != import_result.tx_status.len() {\n    anyhow::bail!(\"import result contains duplicate tx statuses\");\n}\nfor TransactionExecutionStatus { id, result } in import_result.tx_status.iter() {\n    if db.update_tx_status(id, placeholder)?.is_some() {\n        anyhow::bail!(\"tx {} already indexed; block processed twice?\", id);\n    }\n}","typeGuard":null,"tryCatchPattern":"match update_block_metadata(&import_result, flag, &mut db) {\n    Ok(()) => Ok(()),\n    Err(e) if e.to_string().contains(\"status already exists\") => {\n        // duplicate processing: verify heights, and for intentional re-index wipe the off-chain DB first\n        anyhow::bail!(\"duplicate import detected: {}\", e)\n    }\n    Err(e) => Err(e),\n}","preventionTips":["Resume off-chain workers from the off-chain DB's recorded height, never from an earlier block.","Wipe the off-chain DB before any full re-index.","Deduplicate import_result.tx_status at the producer if duplicates are possible.","Restore on-chain and off-chain DBs only from consistent snapshot pairs."],"tags":["off-chain","worker","duplicate","transactions","rust"],"backgroundTag":null,"analyzedSha":"b9d4d170da3a31c9ace5f963d633b326348e0d42","analyzedAt":"2026-08-16T08:56:42.692Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}