unionlabs/union · warning · RpcStatusError

Malformed response

Error message

Malformed response

What it means

RpcStatusError thrown after a successful HTTP 200 from a Cosmos RPC probe: the JSON-RPC response parsed fine, but data.result.sync_info and/or data.result.node_info are missing, so the payload is not shaped like a CometBFT "status" result. The offending payload is attached to the error for inspection.

Source

Thrown at app2/src/routes/nodes/+page.svelte:82

      if (type === "cosmos") {
        const { result: res, duration } = await withTiming(async () =>
          fetch(url, {
            method: "POST",
            headers: { "Content-Type": "application/json" },
            body: JSON.stringify({
              jsonrpc: "2.0",
              id: 1,
              method: "status",
              params: [],
            }),
          })
        )
        if (!res.ok) {
          throw new RpcStatusError("cosmos", url, `HTTP ${res.status} - ${res.statusText}`)
        }
        const data = await res.json()
        if (!(data?.result?.sync_info && data?.result?.node_info)) {
          throw new RpcStatusError("cosmos", url, "Malformed response", data)
        }
        return {
          url,
          type: "cosmos",
          responseTimeMs: duration,
          status: {
            kind: "cosmos",
            latestBlockHeight: Number(data.result.sync_info.latest_block_height),
            catchingUp: data.result.sync_info.catching_up,
            moniker: data.result.node_info.moniker,
            network: data.result.node_info.network,
          },
        }
      }
      if (type === "evm") {
        const { result: res, duration } = await withTiming(async () =>
          fetch(url, {
            method: "POST",

View on GitHub (pinned to 031785bb6d)

Solutions

  1. Check the attached data payload: if it has an error field, fix the underlying JSON-RPC problem (method/rate limit/auth)
  2. Move the URL to the correct list (EVM endpoints belong to the eth_blockNumber probe)
  3. Use a real CometBFT RPC endpoint (port 26657) that supports the "status" method
Defensive patterns

Strategy: type-guard

Validate before calling

const data = await res.json()
const isCosmosStatusResult = (d: unknown): d is { result: { sync_info: unknown; node_info: unknown } } =>
  typeof d === "object" && d !== null &&
  "result" in d &&
  typeof (d as any).result === "object" &&
  (d as any).result !== null &&
  "sync_info" in (d as any).result &&
  "node_info" in (d as any).result

if (!isCosmosStatusResult(data)) {
  // classify: EVM node vs JSON-RPC error, then mark endpoint misconfigured
}

Type guard

const isCosmosStatusPayload = (d: any): d is { result: { sync_info: { latest_block_height: string; catching_up: boolean }; node_info: { moniker: string; network: string } } } =>
  Boolean(d?.result?.sync_info && d?.result?.node_info)

Try / catch

try {
  status = await checkCosmos(url)
} catch (error) {
  if (error instanceof RpcStatusError && error.message === "Malformed response") {
    // inspect error.data: presence of .error means RPC-level failure; a hex .result means it is an EVM endpoint
  }
  throw error
}

Prevention

When it happens

Trigger: POSTing {method:"status"} to an endpoint that returns 200 with a different body shape: an EVM JSON-RPC node (returns {result:"0x..."}), a JSON-RPC error object {error:{...}}, a REST/LCD gateway, or an HTML/JSON welcome page from a proxy.

Common situations: Mixing up node types when adding URLs to the status checker (an Ethereum RPC in the Cosmos list); endpoints fronted by proxies that rewrite responses; JSON-RPC errors (rate limit, invalid method) that still use HTTP 200.

Understand the failure class

Related errors


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