unionlabs/union · error · anyhow::Error
timed out after {:?}
Error message
timed out after {:?} What it means
`CosmosClient::wait_for_event` wraps a poll loop (tx_search per block height, 5s sleep between rounds) in `tokio::time::timeout(max_wait, ...)`. This error means the deadline elapsed before `expected_event_count` matching IBC module events were found — the event never showed up in the scanned window, not that an RPC request failed.
Source
Thrown at tools/union-test/src/cosmos.rs:256
if let Some(found) = filter_fn(&ibc_evt) {
events.push(found);
}
}
}
if seen >= resp.total_count as usize {
break;
}
page = page.checked_add(1).unwrap();
}
height += 1;
}
tokio::time::sleep(Duration::from_secs(5)).await;
}
})
.await
.map_err(|_| anyhow::anyhow!("timed out after {:?}", max_wait))?
}
pub async fn wait_for_create_client_id(
&self,
max_wait: Duration,
) -> anyhow::Result<helpers::CreateClientConfirm> {
Ok(self
.wait_for_event(
|evt| {
if let ModuleEvent::WasmCreateClient { client_id, .. } = evt {
Some(helpers::CreateClientConfirm {
client_id: client_id.raw(),
})
} else {
None
}
},
max_wait,View on GitHub (pinned to 031785bb6d)
Solutions
- Increase the `max_wait` Duration passed by the caller
- Start the wait before (or immediately after) submitting the transaction, not >10 blocks later
- Confirm the chain is progressing (latest_block_height advances between poll rounds)
- Dump raw tx_search events for the tx's height and compare event type/attributes against the filter
- If events deserialize-fail silently, align the union-test version with the chain's event schema
Example fix
// before let evt = client.wait_for_create_client_id(Duration::from_secs(60)).await?; // after let evt = client.wait_for_create_client_id(Duration::from_secs(600)).await?;
Defensive patterns
Strategy: retry
Validate before calling
// pre-flight: confirm the chain is making progress before waiting let s1 = client.rpc.status().await?.sync_info.latest_block_height; tokio::time::sleep(Duration::from_secs(5)).await; let s2 = client.rpc.status().await?.sync_info.latest_block_height; anyhow::ensure!(s2 > s1, "chain not producing blocks; wait_for_event would time out");
Try / catch
match client.wait_for_event(filter, max_wait, n).await {
Ok(evts) => { /* ... */ }
Err(e) if e.to_string().contains("timed out after") => {
// re-check chain liveness and the tx was actually submitted, then retry with a longer window
tokio::time::sleep(Duration::from_secs(10)).await;
client.wait_for_event(filter, max_wait * 2, n).await?
}
Err(e) => return Err(e),
} Prevention
- Start event waits before or immediately after submitting the transaction (events older than ~10 blocks are missed)
- Size max_wait to chain block time plus expected processing, with margin for slow devnets
- Log the tx height you expect the event at so timeouts are diagnosable
When it happens
Trigger: Waiting for create-client / packet-recv / delegate events that are never emitted: chain or relayer halted; the event fired more than ~10 blocks before the wait started (the scan begins at `latest_block_height - 10` so older events are missed); the filter_fn never matches the emitted ModuleEvent variant; expected_event_count is larger than the number of events actually produced.
Common situations: Devnet validators stuck or not producing blocks; test waits long after submitting the tx; RPC node whose /status lags; serde schema drift between union-test's ModuleEvent and the chain's event attributes so matching events are silently skipped.
Understand the failure class
- Timeouts: ETIMEDOUT, deadlines, and hung requests — what actually expires when a request times out.
Related errors
- timed out after {:?}
- wait_for_packet_recv failed: {:?}
- wait_for_packet_ack failed: {:?}
- wait_for_packet_timeout failed: {:?}
- wait_for_update_client failed: {:?}
AI-assisted analysis of unionlabs/union@031785bb6d (2026-08-16).
Data as JSON: /api/errors/b9307e62d26841ad.
Report an issue: GitHub.