unionlabs/union · error · anyhow::Error

timed out after {:?}

Error message

timed out after {:?}

What it means

`EvmClient::wait_for_event` wraps its polling loop (checks block number every 10s, scans each new block's logs filtered by `ibc_handler_address`) in `tokio::time::timeout(timeout, ...)`; this error means the deadline elapsed before `expected_event_count` matching IBC events were observed.

Source

Thrown at tools/union-test/src/evm.rs:191

                            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))?
    }

    pub async fn wait_for_create_client(
        &self,
        timeout: Duration,
    ) -> anyhow::Result<helpers::CreateClientConfirm> {
        Ok(self
            .wait_for_event(
                |e| match e {
                    IbcEvents::CreateClient(ev) => Some(helpers::CreateClientConfirm {
                        client_id: ev.client_id,
                    }),
                    _ => None,
                },
                timeout,
                1,
            )
            .await?

View on GitHub (pinned to 031785bb6d)

Solutions

  1. Increase the `timeout` Duration passed to the wait helper
  2. Verify `ibc_handler_address` is the deployed IBC contract whose logs you need
  3. Confirm the chain produces blocks and the relayer is running
  4. Start the wait before triggering the action that emits the event

Example fix

// before
let evt = evm.wait_for_create_client(Duration::from_secs(120)).await?; 
// after
let evt = evm.wait_for_create_client(Duration::from_secs(1200)).await?;
Defensive patterns

Strategy: retry

Validate before calling

// pre-flight: chain is producing blocks
let b1 = evm.provider.get_block_number().await?;
tokio::time::sleep(Duration::from_secs(10)).await;
let b2 = evm.provider.get_block_number().await?;
anyhow::ensure!(b2 > b1, "EVM chain stalled; wait_for_event will time out");

Try / catch

match evm.wait_for_event(filter, timeout, n).await {
    Ok(evts) => Ok(evts),
    Err(e) if e.to_string().contains("timed out after") => {
        // verify relayer + handler address, then retry with a longer timeout
        evm.wait_for_event(filter, timeout * 2, n).await
    }
    Err(e) => Err(e),
}

Prevention

When it happens

Trigger: The watched event never lands: relayer stopped so packets are never received/acked; `ibc_handler_address` is wrong so the relevant logs are filtered out; the event fired before the wait started (scan begins at the block number at wait start); the EVM chain stalled.

Common situations: Relayer down between devnets; timeout too short for slow proof-verification chains; test fixture configured with a stale handler address; anvil snapshot reverted past the emitting block.

Understand the failure class

Related errors


AI-assisted analysis of unionlabs/union@031785bb6d (2026-08-16). Data as JSON: /api/errors/6c20b757f261bd98. Report an issue: GitHub.