{"record":{"id":"186432a72def64be","repo":"tinyhumansai/openhuman","slug":"core-rpc-response-missing-result","errorCode":null,"errorMessage":"Core RPC response missing result","messagePattern":"Core RPC response missing result","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"app/src/services/coreRpcClient.ts","lineNumber":763,"sourceCode":"      throw new CoreRpcError(httpMessage, kind, response.status);\n    }\n\n    const json = (await response.json()) as JsonRpcResponse<T>;\n\n    if (json.error) {\n      coreRpcError('HTTP error response', {\n        id: payload.id,\n        method: payload.method,\n        error: json.error,\n      });\n      const rawMessage = json.error.message || 'Core RPC returned an error';\n      const kind = classifyRpcError(rawMessage, undefined, json.error.data);\n      if (kind === 'auth_expired' && !suppressAuthExpiredEvent)\n        dispatchAuthExpired(payload.method, classifyAuthExpiredReason(rawMessage, undefined));\n      throw new CoreRpcError(rawMessage, kind, undefined, json.error.data);\n    }\n    if (!Object.prototype.hasOwnProperty.call(json, 'result')) {\n      throw new Error('Core RPC response missing result');\n    }\n\n    coreRpcLog('HTTP response', { id: payload.id, method: payload.method });\n    return json.result as T;\n  } catch (err) {\n    coreRpcError('Core RPC call failed', sanitizeError(err));\n    if (err instanceof CoreRpcError) throw err;\n    const message = coreRpcErrorMessage(err);\n    throw new CoreRpcError(message, classifyRpcError(message));\n  }\n}\n","sourceCodeStart":745,"sourceCodeEnd":775,"githubUrl":"https://github.com/tinyhumansai/openhuman/blob/749120085864ce16e0f273c7b86fac7740b39c5b/app/src/services/coreRpcClient.ts#L745-L775","documentation":"The response parsed as JSON and carried no json.error, but also had no own 'result' property — violating the JSON-RPC 2.0 response shape (exactly one of result/error must be present). This is checked with Object.prototype.hasOwnProperty, so a result of undefined or null still passes; only a structurally missing key triggers it.","triggerScenarios":"A proxy, middleware, or misrouted endpoint answering with a different JSON envelope ({success,data}, empty object, or a status object) on a 200; a core build whose handler serializes RpcOutcome without unwrapping to a result field; response body rewritten by a service worker or intercepting layer.","commonSituations":"Pointing the RPC URL at a backend REST route instead of the core /rpc route; a reverse proxy health-check response; version skew where an old core returned a different envelope; test mocks returning {ok:true} directly as the whole body instead of {jsonrpc,result:{ok:true}}.","solutions":["Verify the RPC URL resolves to the core's POST /rpc endpoint (use testCoreRpcConnection / core.ping) — an alien 200 JSON envelope is the usual cause","Reproduce with curl against the same URL+token and inspect the raw body shape","Fix test/mocks to wrap responses as {jsonrpc:'2.0', id, result: ...}","If a proxy sits in front, bypass it or configure it to pass the core response through untouched"],"exampleFix":"// before (mock returning wrong envelope)\nfetchMock.mockResolvedValue({ ok: true, body: { ok: true } });\n\n// after\nfetchMock.mockResolvedValue({ ok: true, body: { jsonrpc: '2.0', id: 1, result: { ok: true } } });","handlingStrategy":"type-guard","validationCode":"function isJsonRpcResultEnvelope(body: unknown): body is { result: unknown } {\n  return !!body && typeof body === 'object' && 'result' in (body as object);\n}","typeGuard":"function hasResultProp(json: unknown): boolean {\n  return Object.prototype.hasOwnProperty.call(json ?? {}, 'result');\n}","tryCatchPattern":"try {\n  return await callCoreRpc({ method, params });\n} catch (err) {\n  if (err instanceof Error && err.message === 'Core RPC response missing result') {\n    // transport reached something that is not the core's /rpc — check URL/proxy\n    throw new ConfigError(`RPC URL does not serve JSON-RPC: ${await getCoreRpcUrl()}`);\n  }\n  throw err;\n}","preventionTips":["Probe with core.ping (testCoreRpcConnection) whenever the RPC URL is user-configured","In tests, wrap mocked bodies as {jsonrpc:'2.0', id, result} — never return payload objects bare","Keep proxies/middleware from rewriting /rpc bodies"],"tags":["rpc","json-rpc","protocol-violation","response-shape","mocking"],"backgroundTag":"malformed-json-rpc-response","analyzedSha":"749120085864ce16e0f273c7b86fac7740b39c5b","analyzedAt":"2026-08-17T21:21:45.363Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}