unionlabs/union · error · anyhow::Error
wait_for_packet_timeout failed: {:?}
Error message
wait_for_packet_timeout failed: {:?} What it means
In the timeout helper (lib.rs:970), source_chain.wait_for_packet_timeout(packet_hash, timeout) failed: the expected timeout event (the packet being returned/refunded on the source chain after failing to be delivered) was not observed within the deadline. A timeout event only fires after the packet's timeout height/timestamp passes AND the relayer submits the timeout proof — so this usually means the relayer did not process the timeout, or the configured wait is shorter than timeout-height plus relay time.
Source
Thrown at tools/union-test/src/lib.rs:970
hash
}
Err(e) => {
anyhow::bail!("send_ibc_transaction failed: {:?}", e);
}
};
println!(
"Packet sent from {} to {} with hash: {}",
source_chain.chain_id(),
destination_chain.chain_id(),
packet_hash
);
match source_chain
.wait_for_packet_timeout(packet_hash, timeout)
.await
{
Ok(evt) => Ok(evt),
Err(e) => anyhow::bail!("wait_for_packet_timeout failed: {:?}", e),
}
}
pub async fn send_and_get_height<Src: ChainEndpoint, Dst: ChainEndpoint>(
&self,
source_chain: &Src,
contract: Src::Contract,
msg: Src::Msg,
destination_chain: &Dst,
timeout: Duration,
signer: &Src::ProviderType,
) -> anyhow::Result<u64> {
let (packet_hash, height) = match source_chain
.send_ibc_transaction(contract.clone(), msg.clone(), signer)
.await
{
Ok(hash) => {
println!("send_ibc_tx succeeded with hash: {:?}", hash);View on GitHub (pinned to 031785bb6d)
Solutions
- Verify the destination really did NOT receive the packet (if it did, the test premise is wrong — expect recv/ack instead).
- Make sure the relayer is running and configured to submit timeout (timeout_on_close/packet timeout) messages.
- Set the packet timeout height/timestamp close enough that the timeout becomes provable within the wait window, and enlarge the wait Duration accordingly.
- Check the source chain event subscription stayed alive for the whole window.
Example fix
// before: packet timeout height far in the future let msg = transfer_msg(amount, recipient, timeout_height + 1000); // after: tight timeout height so the timeout is provable within the wait let msg = transfer_msg(amount, recipient, timeout_height + 10);
Defensive patterns
Strategy: retry
Validate before calling
// a timeout event requires the timeout to actually be provable first
let current = src.current_height().await?;
anyhow::ensure!(current >= packet_timeout_height, "packet not yet timed out at height {current} < {packet_timeout_height}"); Try / catch
let evt = source_chain.wait_for_packet_timeout(packet_hash, timeout)
.await
.with_context(|| format!("no timeout event for {packet_hash}; was it actually received?"))?; Prevention
- Set the packet timeout height only a few blocks ahead and compute the wait as timeout_delta*block_time + relay_slack.
- First verify (query) that the destination did not receive the packet; a received packet can never time out.
When it happens
Trigger: Relayer not running/confined so nobody submits the timeout proof, the packet's timeout height set far in the future so the wait expired first, destination actually received the packet (so no timeout will ever occur), or source RPC subscription failure.
Common situations: Test sets a timeout height hundreds of blocks ahead but waits only seconds; relayer config skips timeout msgs; the 'unreachable' destination turned out reachable, so the packet got recv'd/acked instead of timing out.
Understand the failure class
- Timeouts: ETIMEDOUT, deadlines, and hung requests — what actually expires when a request times out.
Related errors
- wait_for_packet_recv failed: {:?}
- wait_for_packet_ack failed: {:?}
- wait_for_update_client failed: {:?}
- timed out after {:?}
- timed out after {:?}
AI-assisted analysis of unionlabs/union@031785bb6d (2026-08-16).
Data as JSON: /api/errors/a87b761b6d8b33e4.
Report an issue: GitHub.