tinyhumansai/openhuman · error

[transport:cloud] ${method} timed out after ${this.timeoutMs

Error message

[transport:cloud] ${method} timed out after ${this.timeoutMs}ms

What it means

Thrown when `fetch` in `CloudHttpTransport.call` rejects and the shared `AbortController` is aborted. The controller is tripped either by the internal `setTimeout(this.timeoutMs)` (default 30s) or by the caller's `opts.signal` — the check `controller.signal.aborted` cannot distinguish the two, so a caller-initiated cancel is also reported with this 'timed out' message. The timeout exists to bound cloud-core round trips, which the class docs note use 'a longer default timeout' than LAN.

Source

Thrown at app/src/services/transport/CloudHttpTransport.ts:66

    if (this.bearerToken) {
      headers.Authorization = `Bearer ${this.bearerToken}`;
    }

    const controller = new AbortController();
    const timeoutId = setTimeout(() => controller.abort(), this.timeoutMs);
    opts?.signal?.addEventListener('abort', () => controller.abort());

    let response: Response;
    try {
      response = await fetch(this.rpcUrl, {
        method: 'POST',
        headers,
        body: JSON.stringify(payload),
        signal: controller.signal,
      });
    } 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')) {

View on GitHub (pinned to a221052e0d)

Solutions

  1. Pass a larger `timeoutMs` to the CloudHttpTransport constructor for known-slow methods
  2. Retry idempotent calls with exponential backoff — transient cloud latency is the most common cause
  3. Verify the cloud core URL is reachable and responsive (a quick `openhuman.ping` via the same transport)
  4. If you pass `opts.signal`, check whether your own cancellation produced the message before debugging timeouts

Example fix

// before
const t = new CloudHttpTransport(url, token); // 30s default
await t.call('openhuman.memory_sync', {});

// after
const t = new CloudHttpTransport(url, token, 120_000);
await t.call('openhuman.memory_sync', {});
Defensive patterns

Strategy: retry

Type guard

function isCloudTimeout(e: unknown): boolean {
  return e instanceof Error && e.message.startsWith('[transport:cloud]') && e.message.includes('timed out');
}

Try / catch

for (let attempt = 1; attempt <= 3; attempt++) {
  try { return await transport.call(m, p); }
  catch (e) {
    if (!isCloudTimeout(e) || attempt === 3) throw e;
    await sleep(2 ** attempt * 500); // 1s, 2s backoff
  }
}

Prevention

When it happens

Trigger: A cloud-core RPC exceeding the configured timeoutMs: slow cold-start on the remote core, a heavy method (memory sync, document generation) over high latency, or the cloud endpoint's connection stalling. Also any caller passing its own `signal` that aborts mid-flight.

Common situations: Mobile/high-latency network to the cloud region; default 30s left in place for an operation known to take minutes; retry storms amplifying latency; caller cancellation misread as a timeout in logs.

Understand the failure class

Related errors


AI-assisted analysis of tinyhumansai/openhuman@a221052e0d (2026-08-16). Data as JSON: /api/errors/197bfc1c99aa09bf. Report an issue: GitHub.