{"record":{"id":"a9295e08391d8928","repo":"nautechsystems/nautilus_trader","slug":"execution-intent-intent-id-has-no-current-hash","errorCode":null,"errorMessage":"Execution intent {intent_id} has no current hash","messagePattern":"Execution intent (.+?) has no current hash","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/adapters/blockchain/src/execution/client.rs","lineNumber":1832,"sourceCode":"            stable_head.hash == head.hash,\n            \"Canonical head changed during signer-nonce replacement scan\"\n        );\n        Ok(found)\n    }\n\n    fn release_slot(&self) {\n        *self.in_flight.lock().expect(\"in-flight mutex poisoned\") = None;\n    }\n}\n\nfn current_execution_hash(\n    intent_id: i64,\n    hashes: &[ExecutionTransactionHashRow],\n) -> anyhow::Result<&ExecutionTransactionHashRow> {\n    let mut current = hashes.iter().filter(|row| row.current);\n    let row = current\n        .next()\n        .ok_or_else(|| anyhow::anyhow!(\"Execution intent {intent_id} has no current hash\"))?;\n    anyhow::ensure!(\n        current.next().is_none(),\n        \"Execution intent {intent_id} has more than one current hash\"\n    );\n    Ok(row)\n}\n\n/// Polls for the receipt of a broadcast transaction until it exists or the poll bound\n/// is exhausted. A `null` receipt result is a legitimate pending response.\n#[cfg(test)]\nasync fn poll_for_receipt(\n    http_rpc_client: &BlockchainHttpRpcClient,\n    tx_hash: &B256,\n    max_polls: u32,\n    interval: Duration,\n) -> anyhow::Result<Option<RpcTransactionReceipt>> {\n    let mut last_error = None;\n    let mut observed_pending = false;","sourceCodeStart":1814,"sourceCodeEnd":1850,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/2114cf6f761429e0adb5ca9596fcd7b895b16011/crates/adapters/blockchain/src/execution/client.rs#L1814-L1850","documentation":"current_execution_hash() filters a reconciliation-loaded intent's transaction-hash history for the row flagged current = TRUE and found none. Every intent past the prepared/signed stage must have exactly one current hash (the hash reconciliation should track), so the table invariant is broken and the intent cannot be replayed.","triggerScenarios":"reconcile_unresolved_execution loading an intent whose execution_transaction_hash rows either are empty or all have current = FALSE: partial writes if the add_execution_transaction_hash commit was lost, manual row deletion, or external tools clearing flags.","commonSituations":"DB crash between intent activation and hash insert; DBAs trimming the hash-history table; a restored-from-backup database where later rows were lost.","solutions":["Inspect the rows: SELECT id, transaction_hash, status, current FROM execution_transaction_hash WHERE intent_id = <id> ORDER BY id;","If rows exist but none is current, set current = TRUE on the newest row matching the intent's on-chain reality (verify with eth_getTransactionByHash)","If no rows exist and nothing was broadcast (intent stuck pre-broadcast), retire the intent (active = FALSE) so reconciliation proceeds","Restore the 'one current hash per intent' invariant and prevent out-of-band edits to these tables"],"exampleFix":"-- before: all rows have current = FALSE\nSELECT id, transaction_hash, current FROM execution_transaction_hash WHERE intent_id = 42;\n-- (3 rows, all current = FALSE)\n\n-- after: flag the newest verified row as current\nUPDATE execution_transaction_hash\nSET current = TRUE\nWHERE id = (SELECT max(id) FROM execution_transaction_hash WHERE intent_id = 42);","handlingStrategy":"try-catch","validationCode":"-- Invariant check before startup: every active intent past signing has exactly one current hash\nSELECT i.id\nFROM execution_intent i\nJOIN execution_transaction_hash h ON h.intent_id = i.id\nWHERE i.active AND i.status NOT IN ('prepared', 'signed')\nGROUP BY i.id\nHAVING count(*) FILTER (WHERE h.current) <> 1;\n-- Zero rows expected; otherwise repair before connect().","typeGuard":null,"tryCatchPattern":"try:\n    client.connect()\nexcept Exception as e:\n    if 'has no current hash' in str(e):\n        # inspect execution_transaction_hash for the intent, verify hashes on-chain,\n        # flag the correct row current = TRUE (or deactivate a never-broadcast intent), then retry\n        ...\n    raise","preventionTips":["Never delete rows from execution_transaction_hash; the client manages the current flag through its replace flow","Run the single-current-hash invariant query as part of pre-startup DB checks"],"tags":["blockchain","postgres","data-integrity","reconciliation","transaction-hash"],"backgroundTag":"data-integrity-violation","analyzedSha":"2114cf6f761429e0adb5ca9596fcd7b895b16011","analyzedAt":"2026-08-21T11:28:30.864Z","schemaVersion":2},"datasetVersion":"2026-08-22T14:17:55.899Z"}