unionlabs/union · error · anyhow::Error
wait_for_packet_ack failed: {:?}
Error message
wait_for_packet_ack failed: {:?} What it means
In `send_and_recv_withdraw_rewards`, after the withdraw-rewards event is seen the code waits for the source chain to observe the packet acknowledgement via `wait_for_packet_ack(packet_hash, timeout)`; failure means no ack event for that hash within the timeout.
Source
Thrown at tools/union-test/src/lib.rs:843
};
println!(
"Packet sent from {} to {} with hash: {}",
source_chain.chain_id(),
destination_chain.chain_id(),
packet_hash
);
let withdraw_rewards = match destination_chain
.wait_for_withdraw_rewards(validator, timeout)
.await
{
Ok(evt) => Ok(evt),
Err(e) => anyhow::bail!("wait_for_packet_recv failed: {:?}", e),
};
match source_chain.wait_for_packet_ack(packet_hash, timeout).await {
Ok(evt) => evt,
Err(e) => anyhow::bail!("wait_for_packet_ack failed: {:?}", e),
};
withdraw_rewards
}
pub async fn send_and_recv_refund<Src: ChainEndpoint, Dst: ChainEndpoint>(
&self,
source_chain: &Src,
contract: Src::Contract,
msg: Src::Msg,
destination_chain: &Dst,
timeout: Duration,
signer: &Src::ProviderType,
) -> anyhow::Result<helpers::PacketRecv> {
let (packet_hash, _height) = match source_chain
.send_ibc_transaction(contract.clone(), msg.clone(), signer)
.await
{View on GitHub (pinned to 031785bb6d)
Solutions
- Increase `timeout`
- Verify relayer health on the destination-to-source direction
- Check destination tx logs to confirm an acknowledgement was written rather than a timeout packet
Example fix
// before
... .await?; // uses Duration::from_secs(120) for the ack wait
// after: size the ack timeout to relayer round-trip latency
match source_chain.wait_for_packet_ack(packet_hash, Duration::from_secs(900)).await {
Ok(evt) => evt,
Err(e) => anyhow::bail!("wait_for_packet_ack failed: {:?}", e),
} Defensive patterns
Strategy: retry
Try / catch
let mut n = 0;
loop {
match source_chain.wait_for_packet_ack(packet_hash, timeout).await {
Ok(evt) => break Ok(evt),
Err(e) if n < 2 => { n += 1; source_chain.wait_for_packet_ack(packet_hash, timeout * 2).await.ok().map(|e| break Ok(e)); continue; }
Err(e) => break Err(anyhow::anyhow!("wait_for_packet_ack failed: {:?}", e)),
}
} Prevention
- Budget ack timeouts for the full round trip (relay + destination execution + relay back)
- Monitor relayer health in both directions for ack-dependent flows
- Check destination receipts to distinguish acks from timeout packets when debugging
When it happens
Trigger: The relayer didn't relay the ack back to the source chain in time; the source chain stalled; or the packet timed out on the destination (timeout packet instead of an ack) so no acknowledgement is ever written.
Common situations: Slow relayers on public testnets; timeouts configured below round-trip relay latency; destination-side errors producing timeout packets rather than acks.
Related errors
- wait_for_packet_recv failed: {:?}
- wait_for_packet_timeout 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/6522a6add00196bf.
Report an issue: GitHub.