tinyhumansai/openhuman · error
Cloud RPC returned an error
Error message
Cloud RPC returned an error
What it means
The cloud core answered 2xx but with a JSON-RPC error envelope whose message was null/undefined — the log line ('[transport:cloud] ← %s error') still captures json.error.message before this generic fallback is thrown. This is the core/application rejecting the method call (unknown method, invalid params, domain error) with an unhelpfully empty message.
Solutions
- Enable DEBUG='transport:cloud:error' — the logErr line prints json.error.message and lets you correlate the code (json.error.code) with the cloud core's error table
- Confirm the method exists on the cloud core (its /schema endpoint) before calling
- Align app and cloud core versions; gate new-method calls on a capability check
- Report empty-message errors upstream — the handler should always fill json.error.message
Example fix
// before
const r = await transport.call<T>('openhuman.meet_list_upcoming', {});
// after
import debug from 'debug';
debug.enable('transport:cloud:error'); // surface json.error.code/message from the logErr line
const r = await transport.call<T>('openhuman.meet_list_upcoming', {}); Defensive patterns
Strategy: try-catch
Type guard
function isCloudRpcEnvelopeError(err: unknown): boolean {
return err instanceof Error && (err.message === 'Cloud RPC returned an error' || err.message.startsWith('[transport:cloud]'));
} Try / catch
try {
return await transport.call<T>(method, params);
} catch (err) {
if (isCloudRpcEnvelopeError(err)) {
// enable DEBUG='transport:cloud:error': json.error.code/message were logged pre-throw
logger.error('cloud core rejected call', { method });
}
throw err;
} Prevention
- Check the cloud core's /schema for method availability before calling new methods
- Keep app and cloud core versions aligned; capability-gate new method calls
- Run with DEBUG='transport:cloud:error' during integration to capture code+message pairs
When it happens
Trigger: Calling a method the cloud core doesn't register (version skew between app and cloud core); params failing server-side validation where the handler returns an error without a message; cloud-side domain failures that omit message fields.
Common situations: App build newer than the deployed cloud core; DomainSet/feature differences on the remote core; API contract drift after a cloud update.
Related errors
- LAN RPC returned an error
- [transport:cloud] response missing result
- Core RPC returned an error
- Core RPC returned an error
- MCP HTTP
AI-assisted analysis of tinyhumansai/openhuman@7491200858 (2026-08-17).
Data as JSON: /api/errors/5c7bb8e662cd0087.
Report an issue: GitHub.
Appendix: 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 7491200858)