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

  1. curl the exact rpcUrl with a JSON-RPC frame and inspect the raw envelope returned
  2. Point the profile at the core's true /rpc endpoint, not a wrapping API route
  3. Disable/adjust any service worker or edge middleware that rewrites POST /rpc bodies
  4. 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

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


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)