unionlabs/union · error · anyhow::Error
get_logs RPC error: {}
Error message
get_logs RPC error: {} What it means
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.
Source
Thrown at tools/union-test/src/evm.rs:173
if events.len() >= expected_event_count {
return Ok(events);
}
if prev_latest >= latest {
tokio::time::sleep(Duration::from_secs(10)).await;
continue;
}
while prev_latest <= latest {
let filter = Filter::new()
.address(alloy::primitives::Address::from(self.ibc_handler_address))
.from_block(prev_latest)
.to_block(prev_latest);
let logs = match self.provider.get_logs(&filter).await {
Ok(logs) => logs,
Err(e) => {
return Err(anyhow::anyhow!("get_logs RPC error: {}", e));
}
};
for log in logs {
if let Ok(ibc_event) = IbcEvents::decode_log(&log.inner)
&& let Some(event) = filter_fn(ibc_event.data)
{
events.push(event);
}
}
prev_latest += 1u64;
}
tokio::time::sleep(Duration::from_secs(10)).await;
}
})
.await
.map_err(|_| anyhow::anyhow!("timed out after {:?}", timeout))?View on GitHub (pinned to 031785bb6d)
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
Example fix
// before
let logs = self.provider.get_logs(&filter).await
.map_err(|e| anyhow::anyhow!("get_logs RPC error: {}", e))?;
// after: retry transient provider errors
let mut last = None;
let logs = loop {
match self.provider.get_logs(&filter).await {
Ok(logs) => break logs,
Err(e) if retries_left(&mut n) => { tokio::time::sleep(Duration::from_secs(2)).await; last = Some(e); }
Err(e) => return Err(anyhow::anyhow!("get_logs RPC error: {}", e)),
}
}; Defensive patterns
Strategy: retry
Validate before calling
// pre-flight: provider answers a cheap call before starting the event wait let _n = evm.provider.get_block_number().await?; // fails fast on a dead endpoint
Try / catch
let mut n = 0;
let logs = loop {
match provider.get_logs(&filter).await {
Ok(logs) => break logs,
Err(e) if n < 3 => { n += 1; tokio::time::sleep(Duration::from_secs(2)).await; }
Err(e) => return Err(anyhow::anyhow!("get_logs RPC error: {}", e)),
}
}; Prevention
- 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
When it happens
Trigger: 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.
Common situations: Shared public RPC under load; local anvil/geth restarting mid-test; provider requiring API keys or allowlists; aggressive block-polling hitting provider quotas.
Related errors
- Missing result field
- transaction height not found
- timed out after {:?}
- Failed to deploy contract: {:?}
- client info not found
AI-assisted analysis of unionlabs/union@031785bb6d (2026-08-16).
Data as JSON: /api/errors/226a6af4a7241925.
Report an issue: GitHub.