tinyhumansai/openhuman · error

Core RPC response missing result

Error message

Core RPC response missing result

What it means

Thrown when a call to the local core returns HTTP 200 with valid JSON that contains neither an `error` field nor a `result` field. Per JSON-RPC 2.0, a response object must have exactly one of `result` or `error`, so this is a malformed/foreign response — the client deliberately refuses to treat `undefined` as a result. It fires after the `json.error` branch, so the server really did answer 'success-shaped' but with no payload.

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 a221052e0d)

Solutions

  1. Verify the resolved RPC URL — log `await getCoreRpcUrl()` and confirm it ends in `/rpc` on the core port from `core_rpc_url`
  2. curl the endpoint directly with a minimal JSON-RPC frame (`{"jsonrpc":"2.0","id":1,"method":"openhuman.ping","params":{}}`) and inspect the raw body
  3. If using a mock/stub server, make it reply with `{jsonrpc:'2.0', id, result:{}}` for every frame
  4. Check for a proxy or interceptor between renderer and core and bypass it for `/rpc`

Example fix

// before (stub server replying empty)
app.post('/rpc', (_req, res) => res.json({}));

// after
app.post('/rpc', (req, res) =>
  res.json({ jsonrpc: '2.0', id: req.body.id, result: { pong: true } })
);
Defensive patterns

Strategy: try-catch

Try / catch

try { const r = await callCoreRpc<T>(m, p); }
catch (e) {
  if (e instanceof Error && e.message === 'Core RPC response missing result') {
    logRpcShapeIssue(m); // endpoint config problem, not a business failure
    return undefined;
  }
  throw e;
}

Prevention

When it happens

Trigger: The RPC URL resolves to an endpoint that returns 200 + JSON without JSON-RPC shape: a health endpoint, a mock/stub server replying `{}`, or a proxy that rewrites the body. Also a core bug or middleware that emits `{jsonrpc, id}` with the result dropped during serialization.

Common situations: `rpcUrl` pointing at `/health` or the wrong port instead of `http://127.0.0.1:<port>/rpc`; running against a hand-rolled test stub that replies `{ok:true}`; an intermediate dev proxy (Vite middleware, service worker) stripping the body; version skew after the wire shape changed.

Related errors


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