{"record":{"id":"98708bf4eec880e7","repo":"tinyhumansai/openhuman","slug":"rpc-method-timed-out-after-timeoutms-ms-98708b","errorCode":null,"errorMessage":"RPC ${method} timed out after ${timeoutMs}ms","messagePattern":"RPC (.+?) timed out after (.+?)ms","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"scripts/debug/goals-live.mjs","lineNumber":196,"sourceCode":"  let res;\n  try {\n    res = await fetch(coreUrl, {\n      method: \"POST\",\n      signal: controller.signal,\n      headers: {\n        \"content-type\": \"application/json\",\n        authorization: `Bearer ${token}`,\n      },\n      body: JSON.stringify({\n        jsonrpc: \"2.0\",\n        id: `goals-${Date.now()}-${Math.random().toString(16).slice(2)}`,\n        method,\n        params,\n      }),\n    });\n  } catch (err) {\n    if (err?.name === \"AbortError\")\n      throw new Error(`RPC ${method} timed out after ${timeoutMs}ms`);\n    throw err;\n  } finally {\n    clearTimeout(timer);\n  }\n  const text = await res.text();\n  let body;\n  try {\n    body = JSON.parse(text);\n  } catch {\n    throw new Error(`RPC ${method} returned non-JSON HTTP ${res.status}: ${text.slice(0, 200)}`);\n  }\n  if (!res.ok) throw new Error(`RPC ${method} HTTP ${res.status}`);\n  if (body.error)\n    throw new Error(`RPC ${method} error: ${body.error.message || JSON.stringify(body.error)}`);\n  return body.result;\n}\n\n// RpcOutcome serializes either as the bare value (no logs) or { result, logs }.","sourceCodeStart":178,"sourceCodeEnd":214,"githubUrl":"https://github.com/tinyhumansai/openhuman/blob/a221052e0df5b1f7598fceba7329fd1af95d6699/scripts/debug/goals-live.mjs#L178-L214","documentation":"rpc() in goals-live.mjs wraps every JSON-RPC POST in an AbortController with a per-call timeout (default 600000 ms from --rpc-timeout-ms, 10 s for the internal core.ping probe). When the abort fires, fetch rejects with an AbortError which is translated into this timeout message naming the method and the limit. It exists so a hung core or a slow model provider cannot stall the runner indefinitely.","triggerScenarios":"A goals reflect turn (openhuman.memory_goals_reflect driving the goals_agent) whose LLM inference exceeds --rpc-timeout-ms; a heavily loaded or deadlocked core; provider-side latency (rate limits, retries) pushing a single agent_chat-class call past the limit; setting --rpc-timeout-ms too low (e.g. 30000) for enrichment turns.","commonSituations":"Default 10-minute timeout exceeded on slow/cheap models or long prompts; timeout knob lowered for quick tests and then reused for the expensive reflect case; core busy compiling or serving other requests; network egress to the inference provider throttled.","solutions":["Raise the limit: `--rpc-timeout-ms 1200000` (20 min) or higher for reflect/enrichment turns","Retry the run — provider-side stalls are often transient","Use a faster model via --model, or run only the cheap cases (`--case list --case add`) while iterating","Check core health/load (GET /health, process CPU) to distinguish a hung core from a slow provider","If it happens on every call including core.ping, the core is wedged: restart it (or rerun with --spawn-core for a fresh instance)"],"exampleFix":"// before\nnode scripts/debug/goals-live.mjs --case reflect --rpc-timeout-ms 60000\n# Error: RPC openhuman.memory_goals_reflect timed out after 60000ms\n\n// after\nnode scripts/debug/goals-live.mjs --case reflect --rpc-timeout-ms 900000","handlingStrategy":"retry","validationCode":"// pre-flight: confirm the core answers a cheap ping within a small budget\n// before committing to a long, expensive audit run\ntry {\n  await rpc(coreUrl, token, \"core.ping\", {}, 5_000);\n} catch {\n  console.error(\"core not answering core.ping within 5s — fix connectivity before the audit\");\n  process.exit(2);\n}","typeGuard":"const isTimeoutError = (err) => /timed out after \\d+ms$/.test(err?.message || \"\");","tryCatchPattern":"for (const timeoutMs of [600_000, 1_200_000]) {\n  try {\n    return await rpc(coreUrl, token, method, params, timeoutMs);\n  } catch (err) {\n    if (!/timed out after/.test(err.message) || timeoutMs === 1_200_000) throw err;\n  }\n}","preventionTips":["Size --rpc-timeout-ms to the slowest case (reflect / multi-tool agent turns), not the average","Watch provider status pages when audits time out in bursts — it is usually upstream","Keep the core unloaded while auditing; competing desktop traffic inflates turn latency"],"tags":["rpc","timeout","network","llm-inference"],"backgroundTag":null,"analyzedSha":"a221052e0df5b1f7598fceba7329fd1af95d6699","analyzedAt":"2026-08-16T12:47:06.542Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}