tinyhumansai/openhuman · error
Cloud RPC returned an error
Error message
Cloud RPC returned an error
What it means
Cloud-transport sibling of the core client's error fallback: the JSON parsed fine and contained a JSON-RPC `error` object, but `json.error.message` was nullish, so the literal 'Cloud RPC returned an error' is thrown. The real diagnostic was logged just before via `logErr('[transport:cloud] ← %s error: %s', ...)` but is not propagated on the thrown value — unlike `CoreRpcError`, this is a plain `Error` with no kind/data.
Source
Thrown at app/src/services/transport/CloudHttpTransport.ts:82
} catch (err) {
if (controller.signal.aborted) {
throw new Error(`[transport:cloud] ${method} timed out after ${this.timeoutMs}ms`);
}
throw err;
} finally {
clearTimeout(timeoutId);
}
if (!response.ok) {
const text = await response.text();
throw new Error(`[transport:cloud] HTTP ${response.status}: ${text || response.statusText}`);
}
const json = (await response.json()) as JsonRpcResponse<T>;
if (json.error) {
logErr('[transport:cloud] ← %s error: %s', method, json.error.message);
throw new Error(json.error.message ?? 'Cloud RPC returned an error');
}
if (!Object.prototype.hasOwnProperty.call(json, 'result')) {
throw new Error('[transport:cloud] response missing result');
}
log('[transport:cloud] ← %s id=%d ok', method, id);
return json.result as T;
}
async *stream<T>(
method: string,
params: unknown,
opts?: { signal?: AbortSignal }
): AsyncIterable<T> {
const result = await this.call<T>(method, params, opts);
yield result;
}
View on GitHub (pinned to a221052e0d)
Solutions
- Enable `DEBUG=transport:cloud:error` to see the raw json.error (message/code) for the failing method
- Check the cloud core's own logs for the request id at that timestamp
- If you control the server, always serialize a non-empty error.message
- Match client/server versions to eliminate shape drift
Defensive patterns
Strategy: try-catch
Try / catch
try { await cloud.call(m, p); }
catch (e) {
if (e instanceof Error && e.message === 'Cloud RPC returned an error') {
// message was empty — pull details from debug logs, then surface a generic banner
logger.warn('empty cloud error frame', { method: m });
}
throw e;
} Prevention
- Run dev builds with DEBUG=transport:cloud:error so empty error frames are still recorded with their code
- If you own the server, enforce non-empty error messages in the RPC layer
- Pin client and cloud-core versions together to avoid error-envelope drift
When it happens
Trigger: Cloud core replying `{error: {code: N}}` with no message — server-side error structs that omit message, or gateway-mangled frames that keep the error envelope but drop fields.
Common situations: Version skew between the client's expected error shape and the cloud core's serialization; debugging blind because the thrown message carries no code — the code is only visible in debug logs.
Related errors
- [transport:cloud] response missing result
- LAN RPC returned an error
- Core RPC returned an error
- [transport:cloud] ${method} timed out after ${this.timeoutMs
- [transport:cloud] HTTP ${response.status}: ${text || respons
AI-assisted analysis of tinyhumansai/openhuman@a221052e0d (2026-08-16).
Data as JSON: /api/errors/5c7bb8e662cd0087.
Report an issue: GitHub.