diff --git a/packages/brain/src/modules/apiServers/ui/startUiServer.ts b/packages/brain/src/modules/apiServers/ui/startUiServer.ts index 1fdab803..e373f5d4 100644 --- a/packages/brain/src/modules/apiServers/ui/startUiServer.ts +++ b/packages/brain/src/modules/apiServers/ui/startUiServer.ts @@ -30,6 +30,17 @@ interface RpcRequest { id: string | number | null; } +function toRpcErrorMessage(error: unknown): string { + if (error == null) return "Unknown error"; + if (typeof error === "string") return error; + if (error instanceof Error) return error.message || error.name || "Unknown error"; + try { + return JSON.stringify(error); + } catch { + return String(error); + } +} + export function startUiServer({ brainDb, blockExplorerApi, @@ -101,7 +112,7 @@ export function startUiServer({ logger.error(error); callback({ jsonrpc: "2.0", - error: { code: -32601, message: error }, + error: { code: -32601, message: toRpcErrorMessage(error) }, id }); } diff --git a/packages/ui/src/socket/socket.ts b/packages/ui/src/socket/socket.ts index 0526fc68..6d476f01 100644 --- a/packages/ui/src/socket/socket.ts +++ b/packages/ui/src/socket/socket.ts @@ -2,6 +2,40 @@ import { io, Socket } from "socket.io-client"; import { RoutesArguments, RoutesReturn, RpcMethodNames } from "./types.js"; import { BRAIN_UI_DOMAIN, Network } from "@stakingbrain/common"; +function toErrorMessage(value: unknown): string { + if (value == null) return "Unknown error"; + if (typeof value === "string") return value; + if (value instanceof Error) return value.message || value.name || "Unknown error"; + + if (typeof value === "object") { + const record = value as Record; + // Common JSON-RPC shape: { code, message, data } + const message = record.message; + + if (typeof message === "string") return message; + if (message instanceof Error) return message.message || message.name || "Unknown error"; + + // In this repo the backend currently sends `message: error` where error can be an object. + if (message && typeof message === "object") { + const nested = message as Record; + if (typeof nested.message === "string") return nested.message; + try { + return JSON.stringify(message); + } catch { + return String(message); + } + } + + try { + return JSON.stringify(value); + } catch { + return String(value); + } + } + + return String(value); +} + class RpcClient { private socket: Socket; @@ -33,7 +67,10 @@ class RpcClient { // eslint-disable-next-line @typescript-eslint/no-explicit-any this.socket.emit("rpc", rpcRequest, (response: any) => { if (response.error) { - reject(response.error); + const err = new Error(toErrorMessage(response.error)); + // Preserve the raw JSON-RPC error payload for debugging if needed. + (err as Error & { rpcError?: unknown }).rpcError = response.error; + reject(err); } else { resolve(response.result as RoutesReturn[T]); }