{"record":{"id":"197bfc1c99aa09bf","repo":"tinyhumansai/openhuman","slug":"transport-cloud-method-timed-out-after-this","errorCode":null,"errorMessage":"[transport:cloud] ${method} timed out after ${this.timeoutMs}ms","messagePattern":"\\[transport:cloud\\] (.+?) timed out after (.+?)ms","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"app/src/services/transport/CloudHttpTransport.ts","lineNumber":66,"sourceCode":"    if (this.bearerToken) {\n      headers.Authorization = `Bearer ${this.bearerToken}`;\n    }\n\n    const controller = new AbortController();\n    const timeoutId = setTimeout(() => controller.abort(), this.timeoutMs);\n    opts?.signal?.addEventListener('abort', () => controller.abort());\n\n    let response: Response;\n    try {\n      response = await fetch(this.rpcUrl, {\n        method: 'POST',\n        headers,\n        body: JSON.stringify(payload),\n        signal: controller.signal,\n      });\n    } catch (err) {\n      if (controller.signal.aborted) {\n        throw new Error(`[transport:cloud] ${method} timed out after ${this.timeoutMs}ms`);\n      }\n      throw err;\n    } finally {\n      clearTimeout(timeoutId);\n    }\n\n    if (!response.ok) {\n      const text = await response.text();\n      throw new Error(`[transport:cloud] HTTP ${response.status}: ${text || response.statusText}`);\n    }\n\n    const json = (await response.json()) as JsonRpcResponse<T>;\n\n    if (json.error) {\n      logErr('[transport:cloud] ← %s error: %s', method, json.error.message);\n      throw new Error(json.error.message ?? 'Cloud RPC returned an error');\n    }\n    if (!Object.prototype.hasOwnProperty.call(json, 'result')) {","sourceCodeStart":48,"sourceCodeEnd":84,"githubUrl":"https://github.com/tinyhumansai/openhuman/blob/a221052e0df5b1f7598fceba7329fd1af95d6699/app/src/services/transport/CloudHttpTransport.ts#L48-L84","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Pass a larger `timeoutMs` to the CloudHttpTransport constructor for known-slow methods","Retry idempotent calls with exponential backoff — transient cloud latency is the most common cause","Verify the cloud core URL is reachable and responsive (a quick `openhuman.ping` via the same transport)","If you pass `opts.signal`, check whether your own cancellation produced the message before debugging timeouts"],"exampleFix":"// before\nconst t = new CloudHttpTransport(url, token); // 30s default\nawait t.call('openhuman.memory_sync', {});\n\n// after\nconst t = new CloudHttpTransport(url, token, 120_000);\nawait t.call('openhuman.memory_sync', {});","handlingStrategy":"retry","validationCode":null,"typeGuard":"function isCloudTimeout(e: unknown): boolean {\n  return e instanceof Error && e.message.startsWith('[transport:cloud]') && e.message.includes('timed out');\n}","tryCatchPattern":"for (let attempt = 1; attempt <= 3; attempt++) {\n  try { return await transport.call(m, p); }\n  catch (e) {\n    if (!isCloudTimeout(e) || attempt === 3) throw e;\n    await sleep(2 ** attempt * 500); // 1s, 2s backoff\n  }\n}","preventionTips":["Size timeoutMs per operation class — 30s default is fine for reads, too small for sync/generation","Retry only idempotent methods; never retry joins/writes blindly","If you pass opts.signal, remember caller aborts are reported with the same 'timed out' message"],"tags":["network","timeout","cloud","abort","transport"],"backgroundTag":null,"analyzedSha":"a221052e0df5b1f7598fceba7329fd1af95d6699","analyzedAt":"2026-08-16T12:47:06.542Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}