{"record":{"id":"99ef2d448c348298","repo":"unionlabs/union","slug":"wait-for-packet-recv-failed","errorCode":null,"errorMessage":"wait_for_packet_recv failed: {:?}","messagePattern":"wait_for_packet_recv failed: (.+?)","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"tools/union-test/src/lib.rs","lineNumber":712,"sourceCode":"                println!(\"send_ibc_tx succeeded with hash: {:?}\", hash);\n                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        match destination_chain\n            .wait_for_packet_recv(packet_hash, timeout)\n            .await\n        {\n            Ok(evt) => Ok(evt),\n            Err(e) => anyhow::bail!(\"wait_for_packet_recv failed: {:?}\", e),\n        }\n    }\n\n    pub async fn send_and_recv_and_ack<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<(helpers::PacketRecv, helpers::PacketAck)> {\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":694,"sourceCodeEnd":730,"githubUrl":"https://github.com/unionlabs/union/blob/031785bb6dc6b957c624e62bc64c184409c97d7b/tools/union-test/src/lib.rs#L694-L730","documentation":"After a successful packet send, `send_and_recv` waits on `destination_chain.wait_for_packet_recv(packet_hash, timeout)`; this error means the receiving chain did not observe a packet-recv event for that hash within the timeout. Almost always a relaying/latency problem, not a code failure.","triggerScenarios":"Relayer between the chains stopped or slow; destination chain halted; timeout shorter than relayer latency plus proof-verification time; broken/expired client or channel so the relayer skips the packet.","commonSituations":"Devnet relayer process not started; timeouts tuned for fast local chains reused on slower testnets; client expiry after chain downtime.","solutions":["Increase the `timeout` passed to send_and_recv","Check that the relayer is running and healthy between the two chains","Verify the IBC client/channel are open and not expired or errored","Confirm the destination chain is producing blocks"],"exampleFix":"// before\nsuite.send_and_recv(src, c, m, dst, Duration::from_secs(120), &signer).await?; \n// after\nsuite.send_and_recv(src, c, m, dst, Duration::from_secs(900), &signer).await?;","handlingStrategy":"retry","validationCode":"// pre-flight: relayer reachable / channels open before waiting for recv\nlet _ = destination_chain.query_channel_end(&port_id, &channel_id).await?; // errors early if the path is broken","typeGuard":null,"tryCatchPattern":"match suite.send_and_recv(src, c, m.clone(), dst, timeout, &signer).await {\n    Ok(r) => Ok(r),\n    Err(e) if e.to_string().contains(\"wait_for_packet_recv failed\") => {\n        check_repeater_health();\n        suite.send_and_recv(src, c, m, dst, timeout * 2, &signer).await\n    }\n    Err(e) => Err(e),\n}","preventionTips":["Start relayers as a setup step and health-check them before packet tests","Size timeouts to relayer latency plus proof verification, with margin","Monitor client/channel expiry so packets aren't silently dropped"],"tags":["rust","ibc","relayer","timeout","packet"],"backgroundTag":null,"analyzedSha":"031785bb6dc6b957c624e62bc64c184409c97d7b","analyzedAt":"2026-08-16T06:24:09.996Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}