{"record":{"id":"89953b89ce317370","repo":"unionlabs/union","slug":"client-info-not-found","errorCode":null,"errorMessage":"client info not found","messagePattern":"client info not found","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"voyager/src/main.rs","lineNumber":502,"sourceCode":"                } => {\n                    let ibc_state = voyager_client\n                        .query_ibc_state(\n                            on.clone(),\n                            ibc_spec_id.clone(),\n                            height,\n                            (ibc_handlers\n                                .get(&ibc_spec_id)\n                                .context(anyhow!(\"unknown IBC spec `{ibc_spec_id}`\"))?\n                                .client_state_path)(client_id.clone())?,\n                        )\n                        .await?;\n\n                    match (ibc_state.state, decode) {\n                        (Some(state), true) => {\n                            let client_info = voyager_client\n                                .client_info(on, ibc_spec_id.clone(), client_id)\n                                .await?\n                                .ok_or(anyhow!(\"client info not found\"))?;\n\n                            let decoded = voyager_client\n                                .decode_client_state(\n                                    client_info.client_type,\n                                    client_info.ibc_interface,\n                                    ibc_spec_id,\n                                    serde_json::from_value(state)\n                                        .expect(\"serialization is infallible; qed;\"),\n                                )\n                                .await?;\n\n                            print_json(&IbcStateResponse {\n                                height: ibc_state.height,\n                                state: Some(decoded),\n                            });\n                        }\n                        (state, _) => {\n                            print_json(&IbcStateResponse {","sourceCodeStart":484,"sourceCodeEnd":520,"githubUrl":"https://github.com/unionlabs/union/blob/031785bb6dc6b957c624e62bc64c184409c97d7b/voyager/src/main.rs#L484-L520","documentation":"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.","triggerScenarios":"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`.","commonSituations":"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.","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."],"exampleFix":"# before\nvoyager rpc client-state --on union --client-id 07-tendermint-0 --ibc-spec-id ibc-classic --decode\n# error: client info not found\n\n# check ownership of the client, then query the right chain\nvoyager rpc client-info --on cosmos-hub --client-id 07-tendermint-0 --ibc-spec-id ibc-classic\n\n# after\nvoyager rpc client-state --on cosmos-hub --client-id 07-tendermint-0 --ibc-spec-id ibc-classic --decode","handlingStrategy":"validation","validationCode":"# confirm the client resolves on that chain before decoding\nvoyager rpc client-info --on \"$CHAIN\" --client-id \"$CLIENT_ID\" --ibc-spec-id \"$SPEC\" >/dev/null \\\n  || { echo \"client $CLIENT_ID not found on $CHAIN\" >&2; exit 2; }","typeGuard":"async fn client_exists(client: &HttpClient, on: &str, spec: &str, id: &str) -> bool {\n    client\n        .client_info(on.to_string(), spec.to_string(), RawClientId::new(id.into()))\n        .await\n        .ok()\n        .flatten()\n        .is_some()\n}","tryCatchPattern":"// treat as data error, not transient: report and skip, do not retry\nmatch maybe_client_info(...).await {\n    Ok(None) => return Err(anyhow!(\"client info not found for {client_id} on {on}\")),\n    Ok(Some(info)) => decode_with(info),\n    Err(e) if is_transport_error(&e) => retry(),\n    Err(e) => return Err(e.into()),\n}","preventionTips":["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."],"tags":["rust","cli","ibc","rpc","data-validation","voyager"],"backgroundTag":null,"analyzedSha":"031785bb6dc6b957c624e62bc64c184409c97d7b","analyzedAt":"2026-08-16T06:24:09.996Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}