{"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/749120085864ce16e0f273c7b86fac7740b39c5b/app/src/services/transport/CloudHttpTransport.ts#L48-L84","documentation":"CloudHttpTransport.call aborts its fetch via AbortController after this.timeoutMs (constructor arg, default 30_000) and reports it as this timeout error. Because the caller-provided opts.signal is also wired to abort the same controller, ANY abort — the caller's own cancellation or the timeout — is reported through this branch as a 'timed out' message; there is no separate cancellation error. The transport is installed by TransportManager for user-configured cloud cores via setActiveCoreTransport, after which every callCoreRpc routes through it.","triggerScenarios":"Any callCoreRpc through an active cloud transport whose round-trip exceeds timeoutMs (default 30s): slow cloud RPC, high-latency link, or a hung cloud core; alternatively a caller aborting its opts.signal, which is misreported with the timeout message.","commonSituations":"Mobile/remote profile on a poor connection with the default 30s budget; a cloud core executing a heavy handler; component unmounts aborting in-flight calls and logs polluting Sentry with pseudo-timeouts; constructing the transport with an undersized timeoutMs.","solutions":["Raise the transport's timeoutMs at construction for known-heavy methods (it is a constructor parameter, not per-call)","Distinguish caller cancellation from real timeout before reporting: check your own signal's aborted state, since the transport folds both into one message","Filter these in Sentry/telemetry by the '[transport:cloud]' prefix or switch on the method name","Verify cloud core health if timeouts are persistent rather than network-driven"],"exampleFix":"// before\nconst t = new CloudHttpTransport(url, token);\n\n// after\nconst t = new CloudHttpTransport(url, token, 60_000); // explicit budget for slow cloud handlers","handlingStrategy":"retry","validationCode":null,"typeGuard":"function isCloudTransportTimeout(err: unknown): boolean {\n  return err instanceof Error && err.message.startsWith('[transport:cloud]') && err.message.includes('timed out');\n}","tryCatchPattern":"const mySignal = new AbortController().signal;\ntry {\n  return await transport.call(method, params, { signal: mySignal });\n} catch (err) {\n  if (isCloudTransportTimeout(err) && !mySignal.aborted && isIdempotent(method)) {\n    return await transport.call(method, params); // true timeout → one retry\n  }\n  if (mySignal.aborted) return cancelled(); // caller cancel mislabeled as timeout\n  throw err;\n}","preventionTips":["Size the transport's timeoutMs for the slowest method you call — it is per-transport, not per-call","Check your own signal before classifying: caller aborts are reported as timeouts here","Filter '[transport:cloud]' timeout messages in telemetry to cut unmount-abort noise"],"tags":["transport","cloud","timeout","abort-controller","remote-core"],"backgroundTag":"request-timeout","analyzedSha":"749120085864ce16e0f273c7b86fac7740b39c5b","analyzedAt":"2026-08-17T21:21:45.363Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}