Description
For their REST-based (non-JSON-RPC) endpoints, both AptosAdapter and SorobanAdapter parse the response body as JSON and return it unconditionally, without ever checking response.status():
cli/src/chains/aptos.rs: get_balance (63-67), get_transaction (69-73), get_block (75-86), get_gas_price (88-91), get_account (93-97), get_history (99-107) — all do Ok(self.client.get(url).send().await?.json().await?) with no status check.
cli/src/chains/soroban.rs: get_balance (84-89), get_account (110-115), get_history (117-126) — same pattern against the Horizon REST API.
Neither the Aptos REST API nor Horizon return non-JSON bodies on error (both return a JSON object with an error message/code even on 400/404), so response.json() succeeds and the error payload is returned as Ok(...).
Verified
reqwest::Response::json() parses the body regardless of status code; it only errors if the body isn't valid JSON. Since Aptos/Horizon error responses ARE valid JSON, e.g. Aptos returns {"message":"Account not found by Address(...)","error_code":"account_not_found",...} with HTTP 404 — this flows straight through as a "successful" Result<Value>. Concretely, in cli/src/cli/handlers.rs's Balance handler (line ~548-578), the Aptos branch scans the returned array for a CoinStore resource; when the value is actually an error object (not an array), result.as_array() is None, found stays false, and it falls through to Self::print_value(&result, pretty) — printing the raw Aptos error JSON with a success exit code, no "Error:" prefix, no indication the address lookup failed. The same applies to Soroban get_balance/get_account/get_history against Horizon.
Suggested fix
Add a status check before/instead of blindly parsing, e.g.:
let response = self.client.get(url).send().await?;
let status = response.status();
let body: Value = response.json().await?;
if !status.is_success() {
let msg = body.get("message").and_then(|m| m.as_str()).unwrap_or("Unknown error");
return Err(anyhow!("{msg} (HTTP {status})"));
}
Ok(body)
applied consistently to every REST call site in aptos.rs and soroban.rs.
Timeframe
Claim window: 96 hours. If this issue is claimed/assigned, please submit a fix within 96 hours of assignment — after that window it may be released back up for grabs.
Community
Questions about this issue or the campaign? Join https://t.me/txioCommunity
Description
For their REST-based (non-JSON-RPC) endpoints, both
AptosAdapterandSorobanAdapterparse the response body as JSON and return it unconditionally, without ever checkingresponse.status():cli/src/chains/aptos.rs: get_balance (63-67), get_transaction (69-73), get_block (75-86), get_gas_price (88-91), get_account (93-97), get_history (99-107) — all doOk(self.client.get(url).send().await?.json().await?)with no status check.cli/src/chains/soroban.rs: get_balance (84-89), get_account (110-115), get_history (117-126) — same pattern against the Horizon REST API.Neither the Aptos REST API nor Horizon return non-JSON bodies on error (both return a JSON object with an error message/code even on 400/404), so
response.json()succeeds and the error payload is returned asOk(...).Verified
reqwest::Response::json()parses the body regardless of status code; it only errors if the body isn't valid JSON. Since Aptos/Horizon error responses ARE valid JSON, e.g. Aptos returns{"message":"Account not found by Address(...)","error_code":"account_not_found",...}with HTTP 404 — this flows straight through as a "successful"Result<Value>. Concretely, incli/src/cli/handlers.rs'sBalancehandler (line ~548-578), the Aptos branch scans the returned array for a CoinStore resource; when the value is actually an error object (not an array),result.as_array()isNone,foundstaysfalse, and it falls through toSelf::print_value(&result, pretty)— printing the raw Aptos error JSON with a success exit code, no "Error:" prefix, no indication the address lookup failed. The same applies to Soroban get_balance/get_account/get_history against Horizon.Suggested fix
Add a status check before/instead of blindly parsing, e.g.:
applied consistently to every REST call site in
aptos.rsandsoroban.rs.Timeframe
Claim window: 96 hours. If this issue is claimed/assigned, please submit a fix within 96 hours of assignment — after that window it may be released back up for grabs.
Community
Questions about this issue or the campaign? Join https://t.me/txioCommunity