unionlabs/union · error
client info not found
Error message
client info not found
What it means
In `voyager rpc client-state --decode`, after the raw client state was successfully fetched (`ibc_state.state` is `Some`), the CLI asks the state module for `ClientInfo` (client type + IBC interface) needed to pick a decoder. The RPC returned `null`, so `.ok_or(anyhow!("client info not found"))` fires. In practice the state module resolves the client type on chain (e.g. `clientTypes(clientId)` on the EVM IBC handler) and yields `None` when the chain has no such client, so the raw path existed but the client is unknown to the IBC contract — or the request targeted the wrong chain.
Source
Thrown at voyager/src/main.rs:502
} => {
let ibc_state = voyager_client
.query_ibc_state(
on.clone(),
ibc_spec_id.clone(),
height,
(ibc_handlers
.get(&ibc_spec_id)
.context(anyhow!("unknown IBC spec `{ibc_spec_id}`"))?
.client_state_path)(client_id.clone())?,
)
.await?;
match (ibc_state.state, decode) {
(Some(state), true) => {
let client_info = voyager_client
.client_info(on, ibc_spec_id.clone(), client_id)
.await?
.ok_or(anyhow!("client info not found"))?;
let decoded = voyager_client
.decode_client_state(
client_info.client_type,
client_info.ibc_interface,
ibc_spec_id,
serde_json::from_value(state)
.expect("serialization is infallible; qed;"),
)
.await?;
print_json(&IbcStateResponse {
height: ibc_state.height,
state: Some(decoded),
});
}
(state, _) => {
print_json(&IbcStateResponse {View on GitHub (pinned to 031785bb6d)
Solutions
- Verify the client exists on that chain first: `voyager rpc client-info --on <chain> --client-id <id> --ibc-spec-id <spec>` and inspect the result.
- Double-check `--on` — use the chain id where the client was actually created, not the counterparty.
- Check the client id for typos and correct sequence number (query `client_state_meta` or the chain's clients).
- If you only need the raw state, drop `--decode` to print it without resolving client info.
- If the client genuinely exists, re-run against the correct height (`--height`) and confirm the state module for that chain is healthy.
Example fix
# before voyager rpc client-state --on union --client-id 07-tendermint-0 --ibc-spec-id ibc-classic --decode # error: client info not found # check ownership of the client, then query the right chain voyager rpc client-info --on cosmos-hub --client-id 07-tendermint-0 --ibc-spec-id ibc-classic # after voyager rpc client-state --on cosmos-hub --client-id 07-tendermint-0 --ibc-spec-id ibc-classic --decode
Defensive patterns
Strategy: validation
Validate before calling
# confirm the client resolves on that chain before decoding
voyager rpc client-info --on "$CHAIN" --client-id "$CLIENT_ID" --ibc-spec-id "$SPEC" >/dev/null \
|| { echo "client $CLIENT_ID not found on $CHAIN" >&2; exit 2; } Type guard
async fn client_exists(client: &HttpClient, on: &str, spec: &str, id: &str) -> bool {
client
.client_info(on.to_string(), spec.to_string(), RawClientId::new(id.into()))
.await
.ok()
.flatten()
.is_some()
} Try / catch
// treat as data error, not transient: report and skip, do not retry
match maybe_client_info(...).await {
Ok(None) => return Err(anyhow!("client info not found for {client_id} on {on}")),
Ok(Some(info)) => decode_with(info),
Err(e) if is_transport_error(&e) => retry(),
Err(e) => return Err(e.into()),
} Prevention
- Validate that the client id is created on the target chain before decode queries.
- Derive client ids programmatically (from client-creation events or `clients` listings) instead of hand-typing them.
- Run the non-decode variant first when exploring; add `--decode` only after confirming the client resolves.
- Pair every `--on` flag with a check that the client id prefix/counterparty matches that chain.
When it happens
Trigger: Running `voyager rpc client-state --on <chain> --client-id <id> --ibc-spec-id <spec> --decode` where the client id does not exist on `--on` (typo, wrong chain, counterparty's client id), the client has not been created yet, or the chain's IBC contract returns an empty client type for that id. Only the `--decode` path hits this: without `decode` the raw state is printed without `client_info`.
Common situations: Mixing up which chain owns a client id (client ids are per-chain, e.g. 07-tendermint-3 on the counterparty); querying a height from before the client was created; renaming/regenesis of chains so old client ids are gone; scripts iterating client ids past the created range.
Related errors
- unknown IBC spec `{ibc_spec_id}`
- config file must be specified
- plugin not found
- no database set in config, queue commands require the `pg-qu
- not implemented
AI-assisted analysis of unionlabs/union@031785bb6d (2026-08-16).
Data as JSON: /api/errors/89953b89ce317370.
Report an issue: GitHub.