tinyhumansai/openhuman · error · CoreRpcError

Unknown core RPC error

Error message

Unknown core RPC error

What it means

The catch-all re-wrap at the bottom of callCoreRpc: something was thrown inside the call flow that was not a CoreRpcError and had no extractable message. coreRpcErrorMessage tries Error.message, bare strings, then object .message/.error fields; 'Unknown core RPC error' means the thrown value was none of those (e.g. undefined/null, a number, an opaque cross-realm object, or an object with an empty message). The original value is logged via coreRpcError('Core RPC call failed', sanitizeError(err)) before re-throwing.

Solutions

  1. Enable the debug logger (DEBUG='core-rpc:error') to see the sanitized original err in 'Core RPC call failed' — the classification is only as good as what was thrown
  2. Find and fix the layer rejecting with a non-Error: make it throw new Error(...) or reject with an Error so a real message propagates
  3. Grep custom fetch middleware / offline shims installed in the webview for bare rejects
  4. If it correlates with going offline, treat kind via classifyRpcError on the message-less path and add a connectivity check before calling

Example fix

// before (a fetch shim rejecting bare)
if (!navigator.onLine) reject(undefined);

// after
if (!navigator.onLine) reject(new Error('offline: network unavailable'));
Defensive patterns

Strategy: try-catch

Type guard

function isWrappedUnknownCoreError(err: unknown): boolean {
  return err instanceof Error && err.message === 'Unknown core RPC error';
}

Try / catch

try {
  return await callCoreRpc({ method, params });
} catch (err) {
  if (isWrappedUnknownCoreError(err)) {
    // enable DEBUG='core-rpc:error' — the sanitized original is logged as 'Core RPC call failed'
    logger.error('core RPC threw a message-less value; enable core-rpc:error to inspect', { method });
  }
  throw err;
}

Prevention

When it happens

Trigger: A rejection with a non-Error value: Promise.reject(undefined), throwing a plain object without message/error keys, an aborted fetch surfacing as an opaque object, or custom fetch wrappers/interceptors rejecting with status codes. Anything that escapes earlier branches (network 'Failed to fetch' keeps its own message; this is for message-less throws).

Common situations: Interceptors (Sentry/fetch shim, offline queues) rejecting with non-Error values; webview-specific fetch implementations throwing DOMException-like objects whose message is empty in release builds; test code rejecting with plain values.

Related errors


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

Appendix: source

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

        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)