{"record":{"id":"5c7bb8e662cd0087","repo":"tinyhumansai/openhuman","slug":"cloud-rpc-returned-an-error","errorCode":null,"errorMessage":"Cloud RPC returned an error","messagePattern":"Cloud RPC returned an error","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"app/src/services/transport/CloudHttpTransport.ts","lineNumber":82,"sourceCode":"    } catch (err) {\n      if (controller.signal.aborted) {\n        throw new Error(`[transport:cloud] ${method} timed out after ${this.timeoutMs}ms`);\n      }\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","sourceCodeStart":64,"sourceCodeEnd":100,"githubUrl":"https://github.com/tinyhumansai/openhuman/blob/749120085864ce16e0f273c7b86fac7740b39c5b/app/src/services/transport/CloudHttpTransport.ts#L64-L100","documentation":"The cloud core answered 2xx but with a JSON-RPC error envelope whose message was null/undefined — the log line ('[transport:cloud] ← %s error') still captures json.error.message before this generic fallback is thrown. This is the core/application rejecting the method call (unknown method, invalid params, domain error) with an unhelpfully empty message.","triggerScenarios":"Calling a method the cloud core doesn't register (version skew between app and cloud core); params failing server-side validation where the handler returns an error without a message; cloud-side domain failures that omit message fields.","commonSituations":"App build newer than the deployed cloud core; DomainSet/feature differences on the remote core; API contract drift after a cloud update.","solutions":["Enable DEBUG='transport:cloud:error' — the logErr line prints json.error.message and lets you correlate the code (json.error.code) with the cloud core's error table","Confirm the method exists on the cloud core (its /schema endpoint) before calling","Align app and cloud core versions; gate new-method calls on a capability check","Report empty-message errors upstream — the handler should always fill json.error.message"],"exampleFix":"// before\nconst r = await transport.call<T>('openhuman.meet_list_upcoming', {});\n\n// after\nimport debug from 'debug';\ndebug.enable('transport:cloud:error'); // surface json.error.code/message from the logErr line\nconst r = await transport.call<T>('openhuman.meet_list_upcoming', {});","handlingStrategy":"try-catch","validationCode":null,"typeGuard":"function isCloudRpcEnvelopeError(err: unknown): boolean {\n  return err instanceof Error && (err.message === 'Cloud RPC returned an error' || err.message.startsWith('[transport:cloud]'));\n}","tryCatchPattern":"try {\n  return await transport.call<T>(method, params);\n} catch (err) {\n  if (isCloudRpcEnvelopeError(err)) {\n    // enable DEBUG='transport:cloud:error': json.error.code/message were logged pre-throw\n    logger.error('cloud core rejected call', { method });\n  }\n  throw err;\n}","preventionTips":["Check the cloud core's /schema for method availability before calling new methods","Keep app and cloud core versions aligned; capability-gate new method calls","Run with DEBUG='transport:cloud:error' during integration to capture code+message pairs"],"tags":["transport","cloud","json-rpc","version-skew","empty-message"],"backgroundTag":"json-rpc-error-response","analyzedSha":"749120085864ce16e0f273c7b86fac7740b39c5b","analyzedAt":"2026-08-17T21:21:45.363Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}