tinyhumansai/openhuman · error
[transport:cloud] response missing result
Error message
[transport:cloud] response missing result
What it means
The cloud core's 2xx response parsed as JSON but the envelope has neither error nor an own 'result' property — a JSON-RPC 2.0 protocol violation from the remote side. Checked with hasOwnProperty, so {result: null} is fine; only a structurally absent result key throws.
Solutions
- curl the exact rpcUrl with a JSON-RPC frame and inspect the raw envelope returned
- Point the profile at the core's true /rpc endpoint, not a wrapping API route
- Disable/adjust any service worker or edge middleware that rewrites POST /rpc bodies
- If the cloud core itself is malformed, capture json.error and file it with the response id for server-side correlation
Example fix
// before
const t = new CloudHttpTransport('https://cloud.example.com/api', token);
// after
const t = new CloudHttpTransport('https://cloud.example.com/rpc', token); Defensive patterns
Strategy: type-guard
Validate before calling
async function servesJsonRpc(url: string, token: string | null): Promise<boolean> {
const r = await fetch(url, {
method: 'POST',
headers: { 'Content-Type': 'application/json', ...(token ? { Authorization: `Bearer ${token}` } : {}) },
body: JSON.stringify({ jsonrpc: '2.0', id: 1, method: 'core.ping', params: {} }),
}).then(x => x.json());
return 'result' in r || 'error' in r;
} Type guard
function isMissingResultEnvelope(err: unknown): boolean {
return err instanceof Error && err.message === '[transport:cloud] response missing result';
} Try / catch
try {
return await transport.call<T>(method, params);
} catch (err) {
if (isMissingResultEnvelope(err)) {
throw new ConfigError(`rpcUrl does not serve raw JSON-RPC 2.0: check gateway/wrapping at ${redact(url)}`);
}
throw err;
} Prevention
- Probe the URL with core.ping and assert the envelope shape before saving a profile
- Never point the transport at API-gateway routes that wrap responses in {success,data}
- Keep service workers/edge middleware off POST /rpc
When it happens
Trigger: A cloud gateway answering 200 with its own envelope ({success, data}) instead of forwarding the JSON-RPC frame; a service worker or CDN rewriting the body; a cloud core bug serializing notifications instead of responses.
Common situations: rpcUrl pointing at an API gateway route that wraps responses; middleware (auth edge, WAF) substituting a JSON status body; mismatched API versions between transport and cloud core.
Related errors
- Cloud RPC returned an error
- Core RPC response missing result
- Core RPC returned an error
- LAN RPC returned an error
- MCP HTTP
AI-assisted analysis of tinyhumansai/openhuman@7491200858 (2026-08-17).
Data as JSON: /api/errors/90a754535ea5255d.
Report an issue: GitHub.
Appendix: source
Thrown at app/src/services/transport/CloudHttpTransport.ts:85
}
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;
}
async isHealthy(): Promise<boolean> {
try {
await this.call('openhuman.ping', {}, { signal: AbortSignal.timeout(5000) });View on GitHub (pinned to 7491200858)