linera-io/linera-protocol · error
unexpected query response: {other:?}
Error message
unexpected query response: {other:?} What it means
The bridge monitor sent a user application query (isDepositProcessed) to a Linera chain via chain_client.query_application, but the returned QueryOutcome was not QueryResponse::User(bytes). Only the User variant carries a GraphQL service response; receiving another variant means the query was answered (or rejected) at the system level instead of being routed to the application's service.
Source
Thrown at linera-bridge/src/monitor/mod.rs:49
use linera_core::{client::ChainClient, environment::Environment};
use linera_execution::{Query, QueryResponse};
use tokio::sync::RwLock;
use crate::proof::DepositKey;
/// Queries the evm-bridge app to check whether a deposit has been processed on Linera.
pub async fn query_deposit_processed<E: Environment>(
chain_client: &ChainClient<E>,
bridge_app_id: ApplicationId,
deposit_key: &DepositKey,
) -> anyhow::Result<bool> {
let hash_hex = format!("0x{}", hex::encode(deposit_key.hash()));
let gql = format!(r#"{{ isDepositProcessed(hash: "{hash_hex}") }}"#);
let query = Query::user_without_abi(bridge_app_id, &GqlRequest { query: gql })?;
let (outcome, _) = chain_client.query_application(query, None).await?;
let response_bytes = match outcome.response {
QueryResponse::User(bytes) => bytes,
other => anyhow::bail!("unexpected query response: {other:?}"),
};
let response: serde_json::Value = serde_json::from_slice(&response_bytes)?;
Ok(response["data"]["isDepositProcessed"].as_bool() == Some(true))
}
/// Queries the wrapped-fungible app for its declared source-ERC-20 decimals.
pub async fn query_wrapped_fungible_decimals<E: Environment>(
chain_client: &ChainClient<E>,
fungible_app_id: ApplicationId,
) -> anyhow::Result<u8> {
let query = Query::user_without_abi(
fungible_app_id,
&GqlRequest {
query: "{ decimals }".to_string(),
},
)?;
let (outcome, _) = chain_client.query_application(query, None).await?;
let response_bytes = match outcome.response {View on GitHub (pinned to 6c226ddcb3)
Solutions
- Verify bridge_app_id: it must be the application id of the published bridge app (match it against the id printed at publish time / the chain's registered applications).
- Confirm the target chain actually has the bridge application registered (query the chain's application list) before calling query_deposit_processed.
- Redeploy or re-register the application if it is missing, then update the relay configuration.
- Handle the error at the call site: treat any non-User response as a configuration fault and stop rather than retry, since retrying with the same ids cannot succeed.
Example fix
// before
let (outcome, _) = chain_client.query_application(query, None).await?;
let QueryResponse::User(bytes) = outcome.response else {
anyhow::bail!("unexpected query response: {:?}", outcome.response);
};
// after: fail with actionable context
let QueryResponse::User(bytes) = outcome.response else {
anyhow::bail!(
"bridge app {bridge_app_id} did not return a user query response \
(got {:?}); is the application registered on chain {}?",
outcome.response, chain_client.chain_id()
);
}; Defensive patterns
Strategy: try-catch
Validate before calling
// Before starting the monitor, verify the bridge app is registered on the target chain // (e.g. query the chain's applications and assert bridge_app_id is present), // so query_deposit_processed cannot hit a system-level response.
Try / catch
match monitor.query_deposit_processed(&key).await {
Ok(processed) => processed,
Err(e) if e.to_string().contains("unexpected query response") => {
// configuration fault: wrong/unregistered app id — do NOT retry blindly
tracing::error!(%bridge_app_id, "bridge app not answering user queries; check registration");
return Err(e);
}
Err(e) => return Err(e),
} Prevention
- Pin app ids in one config source and validate them at relay startup with a smoke query.
- Fail relay startup early if the bridge app fails a trivial user query instead of discovering it mid-operation.
When it happens
Trigger: Calling query_deposit_processed with a bridge_app_id that is not a user application (wrong ApplicationId, or the app was never published/registered on the target chain), or a version/ABI mismatch where the node resolves the query to a system response. The response enum is matched strictly; any non-User variant bails with its Debug form.
Common situations: Misconfigured BRIDGE_APP_ID env/config pointing at a fungible-token app id instead of the bridge app; querying a chain where the bridge application was never registered; deployment drift between the relay config and what is actually published on-chain.
Related errors
- invalid block export configuration: {message}
- transaction {tx_hash} reverted (receipt status 0)
- transaction {tx_hash} not confirmed within {RECEIPT_TIMEOUT:
- Chain listener exited unexpectedly: {result:?}
- EVM scan loop exited unexpectedly: {result:?}
AI-assisted analysis of linera-io/linera-protocol@6c226ddcb3 (2026-08-22).
Data as JSON: /api/errors/1a1fa6e94c4656d6.
Report an issue: GitHub.