{"record":{"id":"226a6af4a7241925","repo":"unionlabs/union","slug":"get-logs-rpc-error","errorCode":null,"errorMessage":"get_logs RPC error: {}","messagePattern":"get_logs RPC error: (.+?)","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"tools/union-test/src/evm.rs","lineNumber":173,"sourceCode":"                if events.len() >= expected_event_count {\n                    return Ok(events);\n                }\n\n                if prev_latest >= latest {\n                    tokio::time::sleep(Duration::from_secs(10)).await;\n                    continue;\n                }\n\n                while prev_latest <= latest {\n                    let filter = Filter::new()\n                        .address(alloy::primitives::Address::from(self.ibc_handler_address))\n                        .from_block(prev_latest)\n                        .to_block(prev_latest);\n\n                    let logs = match self.provider.get_logs(&filter).await {\n                        Ok(logs) => logs,\n                        Err(e) => {\n                            return Err(anyhow::anyhow!(\"get_logs RPC error: {}\", e));\n                        }\n                    };\n                    for log in logs {\n                        if let Ok(ibc_event) = IbcEvents::decode_log(&log.inner)\n                            && let Some(event) = filter_fn(ibc_event.data)\n                        {\n                            events.push(event);\n                        }\n                    }\n\n                    prev_latest += 1u64;\n                }\n\n                tokio::time::sleep(Duration::from_secs(10)).await;\n            }\n        })\n        .await\n        .map_err(|_| anyhow::anyhow!(\"timed out after {:?}\", timeout))?","sourceCodeStart":155,"sourceCodeEnd":191,"githubUrl":"https://github.com/unionlabs/union/blob/031785bb6dc6b957c624e62bc64c184409c97d7b/tools/union-test/src/evm.rs#L155-L191","documentation":"In `EvmClient::wait_for_event`, each one-block-wide `eth_getLogs` filter on the IBC handler address that returns a provider error is converted immediately into this message, aborting the whole wait — no retry is attempted at this level.","triggerScenarios":"The RPC endpoint errors on eth_getLogs: node temporarily down or overloaded; rate limiting on a free/public endpoint; method restricted by the provider; transient network failure between the test and the node.","commonSituations":"Shared public RPC under load; local anvil/geth restarting mid-test; provider requiring API keys or allowlists; aggressive block-polling hitting provider quotas.","solutions":["Point the provider at a healthy RPC endpoint (own node or paid tier) and re-run","If transient, retry the wait call; or patch a retry-with-backoff around get_logs","Check provider rate limits / API key configuration"],"exampleFix":"// before\nlet logs = self.provider.get_logs(&filter).await\n    .map_err(|e| anyhow::anyhow!(\"get_logs RPC error: {}\", e))?; \n// after: retry transient provider errors\nlet mut last = None;\nlet logs = loop {\n    match self.provider.get_logs(&filter).await {\n        Ok(logs) => break logs,\n        Err(e) if retries_left(&mut n) => { tokio::time::sleep(Duration::from_secs(2)).await; last = Some(e); }\n        Err(e) => return Err(anyhow::anyhow!(\"get_logs RPC error: {}\", e)),\n    }\n};","handlingStrategy":"retry","validationCode":"// pre-flight: provider answers a cheap call before starting the event wait\nlet _n = evm.provider.get_block_number().await?; // fails fast on a dead endpoint","typeGuard":null,"tryCatchPattern":"let mut n = 0;\nlet logs = loop {\n    match provider.get_logs(&filter).await {\n        Ok(logs) => break logs,\n        Err(e) if n < 3 => { n += 1; tokio::time::sleep(Duration::from_secs(2)).await; }\n        Err(e) => return Err(anyhow::anyhow!(\"get_logs RPC error: {}\", e)),\n    }\n};","preventionTips":["Use a dedicated/paid RPC endpoint for log polling instead of shared free tiers","Keep block ranges per get_logs call narrow (this code already queries one block at a time)","Watch provider rate-limit headers and back off"],"tags":["rust","evm","rpc","alloy","get-logs"],"backgroundTag":null,"analyzedSha":"031785bb6dc6b957c624e62bc64c184409c97d7b","analyzedAt":"2026-08-16T06:24:09.996Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}