{"record":{"id":"a87b761b6d8b33e4","repo":"unionlabs/union","slug":"wait-for-packet-timeout-failed","errorCode":null,"errorMessage":"wait_for_packet_timeout failed: {:?}","messagePattern":"wait_for_packet_timeout failed: (.+?)","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"tools/union-test/src/lib.rs","lineNumber":970,"sourceCode":"                hash\n            }\n            Err(e) => {\n                anyhow::bail!(\"send_ibc_transaction failed: {:?}\", e);\n            }\n        };\n        println!(\n            \"Packet sent from {} to {} with hash: {}\",\n            source_chain.chain_id(),\n            destination_chain.chain_id(),\n            packet_hash\n        );\n\n        match source_chain\n            .wait_for_packet_timeout(packet_hash, timeout)\n            .await\n        {\n            Ok(evt) => Ok(evt),\n            Err(e) => anyhow::bail!(\"wait_for_packet_timeout failed: {:?}\", e),\n        }\n    }\n\n    pub async fn send_and_get_height<Src: ChainEndpoint, Dst: ChainEndpoint>(\n        &self,\n        source_chain: &Src,\n        contract: Src::Contract,\n        msg: Src::Msg,\n        destination_chain: &Dst,\n        timeout: Duration,\n        signer: &Src::ProviderType,\n    ) -> anyhow::Result<u64> {\n        let (packet_hash, height) = match source_chain\n            .send_ibc_transaction(contract.clone(), msg.clone(), signer)\n            .await\n        {\n            Ok(hash) => {\n                println!(\"send_ibc_tx succeeded with hash: {:?}\", hash);","sourceCodeStart":952,"sourceCodeEnd":988,"githubUrl":"https://github.com/unionlabs/union/blob/031785bb6dc6b957c624e62bc64c184409c97d7b/tools/union-test/src/lib.rs#L952-L988","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before: packet timeout height far in the future\nlet msg = transfer_msg(amount, recipient, timeout_height + 1000);\n\n// after: tight timeout height so the timeout is provable within the wait\nlet msg = transfer_msg(amount, recipient, timeout_height + 10);","handlingStrategy":"retry","validationCode":"// a timeout event requires the timeout to actually be provable first\nlet current = src.current_height().await?;\nanyhow::ensure!(current >= packet_timeout_height, \"packet not yet timed out at height {current} < {packet_timeout_height}\");","typeGuard":null,"tryCatchPattern":"let evt = source_chain.wait_for_packet_timeout(packet_hash, timeout)\n    .await\n    .with_context(|| format!(\"no timeout event for {packet_hash}; was it actually received?\"))?;","preventionTips":["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."],"tags":["ibc","relayer","timeout","rust","test-harness"],"backgroundTag":null,"analyzedSha":"031785bb6dc6b957c624e62bc64c184409c97d7b","analyzedAt":"2026-08-16T06:24:09.996Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}