{"record":{"id":"6e209c0a8d68c349","repo":"nautechsystems/nautilus_trader","slug":"transaction-not-found","errorCode":null,"errorMessage":"Transaction not found","messagePattern":"Transaction not found","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/adapters/dydx/src/grpc/client.rs","lineNumber":518,"sourceCode":"    }\n\n    /// Query transaction by hash.\n    ///\n    /// # Errors\n    ///\n    /// Returns an error if the query fails.\n    pub async fn get_tx(&mut self, hash: &str) -> Result<Tx, anyhow::Error> {\n        let req = GetTxRequest {\n            hash: hash.to_string(),\n        };\n        let response = self.tx.get_tx(req).await?.into_inner();\n\n        if let Some(tx) = response.tx {\n            // Convert through bytes since the types are incompatible\n            let tx_bytes = tx.encode_to_vec();\n            Tx::try_from(tx_bytes.as_slice()).map_err(|e| anyhow::anyhow!(\"{e}\"))\n        } else {\n            anyhow::bail!(\"Transaction not found\")\n        }\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use rstest::rstest;\n\n    use super::*;\n\n    #[rstest]\n    fn test_height_ordering() {\n        let h1 = Height(100);\n        let h2 = Height(200);\n        assert!(h1 < h2);\n        assert_eq!(h1, Height(100));\n    }\n","sourceCodeStart":500,"sourceCodeEnd":536,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/dydx/src/grpc/client.rs#L500-L536","documentation":"`get_tx` queries a transaction by hash; if the node responds without a `tx` field, the method bails with 'Transaction not found' instead of returning a Tx. The node answered the RPC but has no TX stored at that hash.","triggerScenarios":"Querying `get_tx` for a hash that has not been committed yet (broadcast in sync mode, TX still in mempool), a pruned node, or a wrong/typo'd hash.","commonSituations":"Polling for a TX confirmation immediately after a sync-mode broadcast before block inclusion; querying an archive/old hash on a pruned full node; retrying with a hash from a failed broadcast that never landed.","solutions":["Retry with backoff — the TX may simply not be committed yet","Confirm the txhash returned by broadcast_tx is the one queried","Check node pruning settings or query an archive node for old TXs","If the TX never appears, re-check the broadcast result code and re-broadcast if needed"],"exampleFix":"// before\nlet tx = client.get_tx(hash).await?;\n// after\nlet tx = loop {\n    match client.get_tx(hash).await {\n        Ok(tx) => break tx,\n        Err(e) if e.to_string().contains(\"not found\") => {\n            tokio::time::sleep(Duration::from_millis(500)).await;\n        }\n        Err(e) => return Err(e),\n    }\n};","handlingStrategy":"retry","validationCode":"// only query hashes returned by a successful broadcast_tx\nlet hash: String = broadcast_result?; // bail early if broadcast failed","typeGuard":null,"tryCatchPattern":"async fn get_tx_with_retry(c: &Client, h: &str) -> anyhow::Result<Tx> {\n    for _ in 0..10 {\n        match c.get_tx(h).await {\n            Ok(t) => return Ok(t),\n            Err(e) if e.to_string().contains(\"not found\") => tokio::time::sleep(Duration::from_millis(500)).await,\n            Err(e) => return Err(e),\n        }\n    }\n    anyhow::bail!(\"tx {h} not found after retries\")\n}","preventionTips":["Poll with exponential backoff after sync-mode broadcasts","Use the exact txhash from the broadcast response","Query archive nodes for old or pruned transactions","Distinguish 'not yet committed' from 'permanently absent' before re-broadcasting"],"tags":["dydx","blockchain","transaction","lookup"],"backgroundTag":"record-not-found","analyzedSha":"18893faf8b356be3320add8de2f861b0b647cf06","analyzedAt":"2026-09-08T20:49:34.690Z","contentChangedAt":"2026-09-08T20:49:34.690Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}