{"record":{"id":"c076fc3c3715b64f","repo":"jamiepine/voicebox","slug":"rpc-method-json-error-message","errorCode":null,"errorMessage":"RPC ${method}: ${json.error.message}","messagePattern":"RPC \\$\\{method\\}: \\$\\{json\\.error\\.message\\}","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"warning","filePath":"landing/src/lib/token-stats.ts","lineNumber":271,"sourceCode":"    creatorRewardsUsd,\n    circulating,\n    updatedAt: Date.now(),\n    warnings,\n  };\n}\n\n// ── Solana / Helius RPC primitives ───────────────────────────────────────────\n\nasync function rpcCall<T>(rpc: string, method: string, params: unknown): Promise<T> {\n  const res = await fetch(rpc, {\n    method: 'POST',\n    headers: { 'Content-Type': 'application/json' },\n    next: { revalidate: REVALIDATE_S },\n    body: JSON.stringify({ jsonrpc: '2.0', id: 'voicebox', method, params }),\n  });\n  if (!res.ok) throw new Error(`RPC ${method} HTTP ${res.status}`);\n  const json = (await res.json()) as { result?: T; error?: { message: string } };\n  if (json.error) throw new Error(`RPC ${method}: ${json.error.message}`);\n  if (json.result === undefined) throw new Error(`RPC ${method}: empty result`);\n  return json.result;\n}\n\ninterface SupplyResult {\n  value: { amount: string; decimals: number; uiAmount: number | null };\n}\nasync function getTokenSupply(\n  rpc: string,\n): Promise<{ uiAmount: number; decimals: number }> {\n  const r = await rpcCall<SupplyResult>(rpc, 'getTokenSupply', [MINT]);\n  const decimals = r.value.decimals;\n  const uiAmount =\n    r.value.uiAmount ?? Number(r.value.amount) / 10 ** decimals;\n  return { uiAmount, decimals };\n}\n\n// Sum a single owner's balance of the mint across all their token accounts.","sourceCodeStart":253,"sourceCodeEnd":289,"githubUrl":"https://github.com/jamiepine/voicebox/blob/51f49dea198384b4eb6087b72c17057c6eb1c1cd/landing/src/lib/token-stats.ts#L253-L289","documentation":"Thrown by `rpcCall()` in `landing/src/lib/token-stats.ts` (line 271) when the JSON-RPC HTTP layer succeeded (2xx) but the response body carries an `error` object — the standard JSON-RPC 2.0 failure shape. The message embeds the RPC's own error text. Like error 18, the surrounding module isolates this and degrades the affected metric to `null` rather than crashing the page.","triggerScenarios":"Invalid/unmatched mint address passed to `getTokenSupply`/`getAccountInfo` (RPC returns error -32602 invalid param or 'Invalid param: mint'); the method is unsupported by the provider; requesting a slot/block that does not exist; provider-specific rate limit returned as a JSON-RPC error (e.g. Helius -32600 with a rate-limit message); the configured `MINT` constant (`TOKEN_CONTRACT_ADDRESS`) is wrong or the token is on a different network than the RPC.","commonSituations":"`TOKEN_CONTRACT_ADDRESS` constant points at a devnet token while the RPC is mainnet (or vice versa); mint has a checksum/typo; provider deprecated a method; holder-enumeration RPC params malformed.","solutions":["Read the embedded message — it usually states 'Invalid param: mint' or names the bad argument; correct the constant/param it points at.","Confirm `MINT` (`TOKEN_CONTRACT_ADDRESS`) matches the network the RPC serves (mainnet mint on mainnet RPC).","On a provider rate-limit error, switch to a keyed/higher-tier RPC and rely on the ISR cache.","Validate the mint is base58 and 32-44 chars before sending it in params."],"exampleFix":"// before\nconst json = await res.json() as { result?: T; error?: { message: string } };\nif (json.error) throw new Error(`RPC ${method}: ${json.error.message}`);\n\n// after — validate mint before the call to avoid -32602\nfunction assertMint(m: string) {\n  if (!/^[1-9A-HJ-NP-Za-km-z]{32,44}$/.test(m)) throw new Error(`Invalid mint: ${m}`);\n}\nassertMint(MINT);\nconst json = await res.json() as { result?: T; error?: { message: string } };\nif (json.error) throw new Error(`RPC ${method}: ${json.error.message}`);","handlingStrategy":"validation","validationCode":"// Validate the mint before sending it in RPC params\nfunction assertMint(m: string) {\n  if (!/^[1-9A-HJ-NP-Za-km-z]{32,44}$/.test(m)) {\n    throw new Error(`Invalid mint address: ${m}`);\n  }\n}\nassertMint(MINT);","typeGuard":"function isBase58Mint(m: string): boolean {\n  return /^[1-9A-HJ-NP-Za-km-z]{32,44}$/.test(m);\n}","tryCatchPattern":"try {\n  return await rpcCall(rpc, method, params);\n} catch (e) {\n  const msg = (e as Error).message;\n  if (/Invalid param|mint/i.test(msg)) warnings.push(`Bad mint for ${method}`);\n  else warnings.push(`${method}: ${msg}`);\n  return null;\n}","preventionTips":["Validate `TOKEN_CONTRACT_ADDRESS` is base58 and on the same network as the RPC.","Read the embedded RPC error text — it names the offending param.","On a provider rate-limit JSON-RPC error, switch to a higher-tier keyed RPC.","Keep the mint constant in sync with the deployed token."],"tags":["solana","rpc","json-rpc","validation","landing"],"backgroundTag":null,"analyzedSha":"51f49dea198384b4eb6087b72c17057c6eb1c1cd","analyzedAt":"2026-08-12T16:51:42.824Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}