{"record":{"id":"90a754535ea5255d","repo":"tinyhumansai/openhuman","slug":"transport-cloud-response-missing-result","errorCode":null,"errorMessage":"[transport:cloud] response missing result","messagePattern":"\\[transport:cloud\\] response missing result","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"app/src/services/transport/CloudHttpTransport.ts","lineNumber":85,"sourceCode":"      }\n      throw err;\n    } finally {\n      clearTimeout(timeoutId);\n    }\n\n    if (!response.ok) {\n      const text = await response.text();\n      throw new Error(`[transport:cloud] HTTP ${response.status}: ${text || response.statusText}`);\n    }\n\n    const json = (await response.json()) as JsonRpcResponse<T>;\n\n    if (json.error) {\n      logErr('[transport:cloud] ← %s error: %s', method, json.error.message);\n      throw new Error(json.error.message ?? 'Cloud RPC returned an error');\n    }\n    if (!Object.prototype.hasOwnProperty.call(json, 'result')) {\n      throw new Error('[transport:cloud] response missing result');\n    }\n\n    log('[transport:cloud] ← %s id=%d ok', method, id);\n    return json.result as T;\n  }\n\n  async *stream<T>(\n    method: string,\n    params: unknown,\n    opts?: { signal?: AbortSignal }\n  ): AsyncIterable<T> {\n    const result = await this.call<T>(method, params, opts);\n    yield result;\n  }\n\n  async isHealthy(): Promise<boolean> {\n    try {\n      await this.call('openhuman.ping', {}, { signal: AbortSignal.timeout(5000) });","sourceCodeStart":67,"sourceCodeEnd":103,"githubUrl":"https://github.com/tinyhumansai/openhuman/blob/a221052e0df5b1f7598fceba7329fd1af95d6699/app/src/services/transport/CloudHttpTransport.ts#L67-L103","documentation":"Cloud transport strictness check: HTTP was 2xx and the body was valid JSON with no `error` field, but it also had no own `result` property — a malformed JSON-RPC success frame. The transport refuses to coerce `undefined` into a result, so downstream `T`-typed consumers never see phantom values.","triggerScenarios":"Cloud endpoint returning an empty object `{}`, a `{jsonrpc, id}` frame with the result dropped by serialization, or an HTTP 200 HTML/text body that happens to parse as JSON (rare) — more typically a gateway rewriting the response.","commonSituations":"Wrong rpcUrl landing on a status/health route that answers 200 `{}`; API-gateway response transformation; server bug after a wire-shape change; mock cloud returning incomplete frames.","solutions":["Replay the request with curl and inspect the raw body — confirm it is `{jsonrpc:'2.0', id, result:...}`","Verify rpcUrl points at the cloud core's JSON-RPC route, not a health or status endpoint","Disable any gateway/proxy body transformation for this route","Fix the server/mock to always include `result` (even `result: null`) on success"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try { return await cloud.call<T>(m, p); }\ncatch (e) {\n  if (e instanceof Error && e.message === '[transport:cloud] response missing result') {\n    throw new Error(`cloud rpc url is not a JSON-RPC endpoint (method ${m}) — check the connection profile`);\n  }\n  throw e;\n}","preventionTips":["Ping the endpoint with openhuman.ping when a cloud profile is created — shape errors fail fast at setup","Never point the transport at health/status routes; they answer 200 without JSON-RPC frames","Disable gateway body-rewriting on the RPC route"],"tags":["json-rpc","cloud","validation","transport"],"backgroundTag":null,"analyzedSha":"a221052e0df5b1f7598fceba7329fd1af95d6699","analyzedAt":"2026-08-16T12:47:06.542Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}