tinyhumansai/openhuman · error

Core RPC response missing result

Error message

Core RPC response missing result

What it means

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.

Solutions

  1. 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
  2. Reproduce with curl against the same URL+token and inspect the raw body shape
  3. Fix test/mocks to wrap responses as {jsonrpc:'2.0', id, result: ...}
  4. If a proxy sits in front, bypass it or configure it to pass the core response through untouched

Example fix

// before (mock returning wrong envelope)
fetchMock.mockResolvedValue({ ok: true, body: { ok: true } });

// after
fetchMock.mockResolvedValue({ ok: true, body: { jsonrpc: '2.0', id: 1, result: { ok: true } } });
Defensive patterns

Strategy: type-guard

Validate before calling

function isJsonRpcResultEnvelope(body: unknown): body is { result: unknown } {
  return !!body && typeof body === 'object' && 'result' in (body as object);
}

Type guard

function hasResultProp(json: unknown): boolean {
  return Object.prototype.hasOwnProperty.call(json ?? {}, 'result');
}

Try / catch

try {
  return await callCoreRpc({ method, params });
} catch (err) {
  if (err instanceof Error && err.message === 'Core RPC response missing result') {
    // transport reached something that is not the core's /rpc — check URL/proxy
    throw new ConfigError(`RPC URL does not serve JSON-RPC: ${await getCoreRpcUrl()}`);
  }
  throw err;
}

Prevention

When it happens

Trigger: 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.

Common situations: 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}}.

Related errors


AI-assisted analysis of tinyhumansai/openhuman@7491200858 (2026-08-17). Data as JSON: /api/errors/186432a72def64be. Report an issue: GitHub.

Appendix: source

Thrown at app/src/services/coreRpcClient.ts:763

      throw new CoreRpcError(httpMessage, kind, response.status);
    }

    const json = (await response.json()) as JsonRpcResponse<T>;

    if (json.error) {
      coreRpcError('HTTP error response', {
        id: payload.id,
        method: payload.method,
        error: json.error,
      });
      const rawMessage = json.error.message || 'Core RPC returned an error';
      const kind = classifyRpcError(rawMessage, undefined, json.error.data);
      if (kind === 'auth_expired' && !suppressAuthExpiredEvent)
        dispatchAuthExpired(payload.method, classifyAuthExpiredReason(rawMessage, undefined));
      throw new CoreRpcError(rawMessage, kind, undefined, json.error.data);
    }
    if (!Object.prototype.hasOwnProperty.call(json, 'result')) {
      throw new Error('Core RPC response missing result');
    }

    coreRpcLog('HTTP response', { id: payload.id, method: payload.method });
    return json.result as T;
  } catch (err) {
    coreRpcError('Core RPC call failed', sanitizeError(err));
    if (err instanceof CoreRpcError) throw err;
    const message = coreRpcErrorMessage(err);
    throw new CoreRpcError(message, classifyRpcError(message));
  }
}

View on GitHub (pinned to 7491200858)