unionlabs/union · error · anyhow::Error

wait_for_update_client failed: {:?}

Error message

wait_for_update_client failed: {:?}

What it means

After a successful send, send_and_get_height waits on the destination chain for the update-client event tied to the send height via destination_chain.wait_for_update_client(height, timeout). This error means no such update-client event was observed within the timeout: typically the relayer did not push a new consensus/client update covering that height, or the query for the event failed. The helper then cannot report the client update height and bails.

Source

Thrown at tools/union-test/src/lib.rs:1008

            }
            Err(e) => {
                anyhow::bail!("send_ibc_transaction failed: {:?}", e);
            }
        };
        println!(
            "Packet sent from {} to {} with hash: {} and with height: {}",
            source_chain.chain_id(),
            destination_chain.chain_id(),
            packet_hash,
            height
        );

        let update_client_result: anyhow::Result<helpers::UpdateClient> = match destination_chain
            .wait_for_update_client(height, timeout)
            .await
        {
            Ok(evt) => Ok(evt),
            Err(e) => anyhow::bail!("wait_for_update_client failed: {:?}", e),
        };
        println!("Update client event received: {:?}", update_client_result);

        Ok(update_client_result.unwrap().height)
    }

    pub async fn send_and_expect_revert<Src: ChainEndpoint, Dst: ChainEndpoint>(
        &self,
        source_chain: &Src,
        contract: Src::Contract,
        msg: Src::Msg,
        expected_revert_code: u32,
        signer: &Src::ProviderType,
    ) -> anyhow::Result<()> {
        match source_chain
            .send_ibc_transaction(contract.clone(), msg.clone(), signer)
            .await
        {

View on GitHub (pinned to 031785bb6d)

Solutions

  1. Confirm the relayer is running and submitting update-client msgs for the source→destination client pair.
  2. Increase the timeout so it covers the relayer's update cadence plus block times on both chains.
  3. Check the destination client is active (not expired) so updates are accepted.
  4. Verify the height used for the query is the block height the send tx was included in (printed in the 'with height: {}' log).
Defensive patterns

Strategy: retry

Validate before calling

// confirm the destination client of src is active before waiting
let status = dst.query_client_status(src.chain_id()).await?;
anyhow::ensure!(status == ClientStatus::Active, "client not active: {status:?} — updates will not land");

Try / catch

let upd = dst.wait_for_update_client(height, timeout)
    .await
    .with_context(|| format!("no update-client event covering height {height} within {timeout:?}"))?;

Prevention

When it happens

Trigger: No relayer running to submit client updates for the destination's client of the source chain, the update-client message skipped because the client was already current but the event query targets the wrong height, or the timeout is shorter than the relayer's update cadence.

Common situations: Test harness started chains but not the relayer; relayer's client-update frequency configured too low for the test window; expired/allow-update misconfigured client; wrong height passed because the send returned the block of a different node view.

Related errors


AI-assisted analysis of unionlabs/union@031785bb6d (2026-08-16). Data as JSON: /api/errors/0906366bbc288132. Report an issue: GitHub.