{"record":{"id":"611f910c3371adde","repo":"nautechsystems/nautilus_trader","slug":"failed-to-persist-transaction-tx-hash-e-the","errorCode":null,"errorMessage":"Failed to persist transaction {tx_hash}: {e}; the in-flight slot stays occupied","messagePattern":"Failed to persist transaction (.+?): (.+?); the in-flight slot stays occupied","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/adapters/blockchain/src/execution/client.rs","lineNumber":1547,"sourceCode":"                intent_id: prepared.intent_id,\n                nonce: prepared.nonce,\n                tx_hash: prepared.tx_hash,\n                purpose,\n            }));\n        }\n\n        let tx_hash = prepared.tx_hash;\n        self.database\n            .add_execution_transaction_hash(\n                prepared.intent_id,\n                self.chain_id,\n                &tx_hash.to_string(),\n                &prepared.raw_tx,\n            )\n            .await\n            .map(|_| ())\n            .map_err(|e| {\n                anyhow::anyhow!(\n                    \"Failed to persist transaction {tx_hash}: {e}; the in-flight slot stays occupied\"\n                )\n            })\n    }\n\n    /// Broadcasts the signed transaction and classifies the acceptance outcome.\n    async fn broadcast(&self, prepared: &PreparedTransaction) -> anyhow::Result<BroadcastOutcome> {\n        let tx_hash = prepared.tx_hash;\n\n        self.database\n            .record_execution_status(\n                prepared.intent_id,\n                &tx_hash.to_string(),\n                TransactionStatus::Broadcast,\n                None,\n                None,\n                None,\n                None,","sourceCodeStart":1529,"sourceCodeEnd":1565,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/2114cf6f761429e0adb5ca9596fcd7b895b16011/crates/adapters/blockchain/src/execution/client.rs#L1529-L1565","documentation":"After signing, the client persists the transaction hash via add_execution_transaction_hash and that Postgres write failed ({e} carries the DB error). The write happens before any broadcast, but because a cancelled future cannot know whether the row committed, the client deliberately leaves the in-flight slot occupied and returns this error; restart-time reconciliation resolves the intent from whatever actually committed.","triggerScenarios":"fill_and_persist while Postgres is unreachable (connection dropped, pool exhausted, timeout) or the insert violates a constraint; the error text explicitly notes the slot stays occupied to preserve the safety invariant.","commonSituations":"Database failover or restart mid-trade; Postgres connection pool sized too small for the trading loop; network partition between the trading host and the DB host.","solutions":["Do not blindly re-submit: the signed transaction may or may not have been persisted; treat the outcome as ambiguous","Restore database connectivity, then restart/reconnect the client so reconcile_unresolved_execution resolves the intent (it will pick up the signed hash or mark the intent recoverable)","Check the execution_transaction_hash table for the tx_hash from the message to learn which side of the ambiguity you are on","Harden Postgres (pool size, timeouts, HA) so single write failures do not interrupt the persist-before-broadcast path"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"-- Before (re)starting, confirm DB reachability and table health\nSELECT 1;\nSELECT count(*) FROM execution_transaction_hash WHERE intent_id = :active_intent_id;\n-- A healthy store answers quickly; latency/failures here predict the persist error.","typeGuard":null,"tryCatchPattern":"try:\n    await submit_and_wait(order)\nexcept Exception as e:\n    if 'Failed to persist transaction' in str(e):\n        # AMBIGUOUS outcome: do NOT re-submit. Keep wallet/config/store identical,\n        # restore DB, then reconnect so reconcile_unresolved_execution resolves the intent.\n        alert_ops('execution persist failure - reconciliation required')\n        raise","preventionTips":["Treat this error as reconciliation-required, never as retry-eligible: a re-submission risks a duplicate spend","Keep Postgres highly available and the connection pool generously sized relative to order throughput","Always reconnect the same wallet + database after this failure so the occupied slot resolves"],"tags":["blockchain","postgres","write-failure","reconciliation","capital-safety"],"backgroundTag":"database-write-failed","analyzedSha":"2114cf6f761429e0adb5ca9596fcd7b895b16011","analyzedAt":"2026-08-21T11:28:30.864Z","schemaVersion":2},"datasetVersion":"2026-08-22T14:17:55.899Z"}