{"record":{"id":"573a4015b885b1a7","repo":"tinyhumansai/openhuman","slug":"core-rpc-returned-an-error-573a40","errorCode":null,"errorMessage":"Core RPC returned an error","messagePattern":"Core RPC returned an error","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"app/src/services/transport/LocalTransport.ts","lineNumber":84,"sourceCode":"    } catch (err) {\n      if (controller.signal.aborted) {\n        throw new Error(`[transport:local] ${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:local] 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:local] ← %s error: %s', method, json.error.message);\n      throw new Error(json.error.message ?? 'Core RPC returned an error');\n    }\n    if (!Object.prototype.hasOwnProperty.call(json, 'result')) {\n      throw new Error('[transport:local] response missing result');\n    }\n\n    log('[transport:local] ← %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    // Local HTTP doesn't support streaming natively in this project.\n    // Fall back to a single call and yield the result.\n    const result = await this.call<T>(method, params, opts);\n    yield result;","sourceCodeStart":66,"sourceCodeEnd":102,"githubUrl":"https://github.com/tinyhumansai/openhuman/blob/a221052e0df5b1f7598fceba7329fd1af95d6699/app/src/services/transport/LocalTransport.ts#L66-L102","documentation":"The core answered HTTP 200 with a JSON-RPC envelope whose `error` member is truthy — the RPC method failed core-side. This generic text appears only when json.error.message is null/undefined, itself a JSON-RPC 2.0 protocol violation, so it usually means the core (or something in front of it) produced a non-conformant error object with no message.","triggerScenarios":"Calling any openhuman.* method whose handler returns Err where the error serializes without a message field — e.g. {error:{code:-32603}}; a mock/dev server (scripts/mock-api-core.mjs) with message-less error fixtures; a gateway re-serializing JSON-RPC errors.","commonSituations":"Mock backend returning error objects lacking message; a domain handler building RpcError from a code map without a message; version skew between the frontend's method expectations and the core handler's error shape.","solutions":["Log json.error.code — the numeric code often identifies the failure even without a message","Reproduce the call against a real core (./target/debug/openhuman-core serve) and check the core log for the handler error","If you control the server side, always serialize {code, message} per JSON-RPC 2.0","If using the mock server, fix its error fixture to include a message"],"exampleFix":"// before (mock/server error without message)\nres.json({ error: { code: -32603 } });\n\n// after\nres.json({ error: { code: -32603, message: 'agent session not found' } });","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"Catch and treat err.message as unreliable for this case — show a generic failure notice, log the method name and request id, and correlate with the core-side log where the real error text lives.","preventionTips":["Branch RPC error handling on the JSON-RPC error code, not on message text","Keep mock-server error fixtures JSON-RPC 2.0 conformant (code + message)","Assert message presence in server-side error serialization tests"],"tags":["rpc","json-rpc","core","protocol","mock"],"backgroundTag":null,"analyzedSha":"a221052e0df5b1f7598fceba7329fd1af95d6699","analyzedAt":"2026-08-16T12:47:06.542Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}