tinyhumansai/openhuman · error · CoreRpcError

Core RPC HTTP ${response.status}: ${text || response.statusT

Error message

Core RPC HTTP ${response.status}: ${text || response.statusText}

What it means

Thrown by callCoreRpc when the core's /rpc endpoint answers HTTP non-2xx: the body text is read, classifyRpcError maps it to a kind (401 -> auth_expired, which also dispatches the auth-expired event unless suppressed; 429 -> rate_limited; etc.), and a CoreRpcError carrying kind and the HTTP status is thrown. The message embeds the status plus the body text or statusText.

Source

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

          `Core RPC ${payload.method} timed out after ${effectiveTimeoutMs}ms`,
          'timeout'
        );
      }
      throw fetchErr;
    } finally {
      clearTimeout(timeoutId);
    }

    if (!response.ok) {
      const text = await response.text();
      const httpMessage = `Core RPC HTTP ${response.status}: ${text || response.statusText}`;
      const kind = classifyRpcError(text || response.statusText, response.status);
      if (kind === 'auth_expired' && !suppressAuthExpiredEvent)
        dispatchAuthExpired(
          payload.method,
          classifyAuthExpiredReason(text || response.statusText, response.status)
        );
      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');

View on GitHub (pinned to a221052e0d)

Solutions

  1. Branch on the status: 401 -> let the auth-expired flow run (it clears/re-fetches the token; clearCoreRpcTokenCache exists for restarts); 429 -> back off; 5xx -> restart the core and retry
  2. Verify the rpcUrl points at the live core (GET /health and GET /schema on the same origin)
  3. Check core logs at the request timestamp for panics/errors behind a 500
  4. If it follows a core restart, ensure nothing bypasses the token-cache clearing path

Example fix

// before
await callCoreRpc({ method: 'openhuman.flows_list' });

// after
try {
  await callCoreRpc({ method: 'openhuman.flows_list' });
} catch (e) {
  if (e instanceof CoreRpcError && e.kind === 'auth_expired') {
    await clearCoreRpcTokenCache();
    return callCoreRpc({ method: 'openhuman.flows_list' }); // retry with fresh token
  }
  throw e;
}
Defensive patterns

Strategy: try-catch

Validate before calling

// Health-check the endpoint before a burst of RPCs (e.g. after a core restart)
const ok = await fetch(`${rpcBaseUrl}/health`).then(r => r.ok).catch(() => false);
if (!ok) await waitForCoreHealthy();

Type guard

import { CoreRpcError } from '../services/coreRpcClient';
function isAuthExpired(e: unknown): e is CoreRpcError & { status?: number } {
  return e instanceof CoreRpcError && e.kind === 'auth_expired';
}

Try / catch

try {
  return await callCoreRpc(payload);
} catch (e) {
  if (isAuthExpired(e)) {
    clearCoreRpcTokenCache();
    return callCoreRpc(payload); // re-fetch token once, then surface if it repeats
  }
  if (e instanceof CoreRpcError && e.status === 429) { await delay(2000); return callCoreRpc(payload); }
  throw e;
}

Prevention

When it happens

Trigger: 401 with a stale bearer (core restarted and minted a new token while the client cached the old one); 404 from pointing at the wrong port/path; 500/503 when the core process is crashing or its HTTP layer is wedged; any proxy in front of /rpc answering with an error status.

Common situations: Token staleness across core restarts (restartCoreProcess clears the token cache for exactly this reason); misconfigured rpcUrl (leftover port from a previous launch); core panic during a request; rate limiting through a relayed/tunneled transport.

Related errors


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