{"record":{"id":"4f2556fc67401387","repo":"tinyhumansai/openhuman","slug":"rpc-method-http-res-status-4f2556","errorCode":null,"errorMessage":"RPC ${method} HTTP ${res.status}","messagePattern":"RPC (.+?) HTTP (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"scripts/debug/goals-live.mjs","lineNumber":208,"sourceCode":"        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 }.\nfunction unwrap(result) {\n  if (result && typeof result === \"object\" && \"result\" in result && \"logs\" in result) {\n    return { value: result.result, logs: result.logs || [] };\n  }\n  return { value: result, logs: [] };\n}\n\nfunction renderGoals(doc) {\n  const items = doc?.items || [];\n  if (items.length === 0) return \"    (no goals)\";\n  return items.map((g) => `    - [${g.id}] ${g.text}`).join(\"\\n\");\n}","sourceCodeStart":190,"sourceCodeEnd":226,"githubUrl":"https://github.com/tinyhumansai/openhuman/blob/a221052e0df5b1f7598fceba7329fd1af95d6699/scripts/debug/goals-live.mjs#L190-L226","documentation":"If the response parses as JSON but res.ok is false, rpc() throws this bare HTTP-status error. At this layer the request reached an HTTP server that speaks JSON but rejected the request at the transport level — as opposed to error 226, which is a JSON-RPC-level failure inside a 200 response. The two most common causes are 401 (bad/missing bearer) and 404 (wrong path).","triggerScenarios":"401: the bearer is wrong — token from a previous core launch (per-launch hex rotates), token truncated by shell quoting, or readToken picked a stale core.token; 404: --core-url missing the /rpc suffix or pointing at the wrong port; 405: GET sent where only POST is accepted (malformed invocation); 503: core shutting down.","commonSituations":"Core restarted between the time core.token was read and the RPC fired; mixing tokens across staging/prof production workspaces; URL copy-pasted from docs without the /rpc path; reverse proxy in front of the core requiring additional auth.","solutions":["401 → refresh the bearer: re-read the current <workspace>/core.token, pass --token explicitly, or run --spawn-core so the script owns a fresh token","404 → fix the URL to include /rpc and the correct port (default http://127.0.0.1:7788/rpc)","Confirm the endpoint contract with curl: `curl -s -o /dev/null -w '%{http_code}' -X POST <url> -H 'authorization: Bearer <tok>' -H 'content-type: application/json' -d '{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"core.ping\",\"params\":{}}'`","If 5xx, check the core's own logs — it is receiving but failing the request"],"exampleFix":"# before: token from an older core launch\nnode scripts/debug/goals-live.mjs --token $(cat /old/workspace/core.token)\n# Error: RPC openhuman.memory_goals_list HTTP 401\n\n# after: re-read the live workspace's token\nnode scripts/debug/goals-live.mjs --token $(cat ~/.openhuman/users/<id>/workspace/core.token)","handlingStrategy":"validation","validationCode":"// cheap authenticated ping before the audit: surfaces 401/404 immediately\nconst res = await fetch(coreUrl, {\n  method: \"POST\",\n  headers: { \"content-type\": \"application/json\", authorization: `Bearer ${token}` },\n  body: JSON.stringify({ jsonrpc: \"2.0\", id: 1, method: \"core.ping\", params: {} }),\n});\nif (res.status === 401) { console.error(\"stale or wrong bearer — refresh core.token\"); process.exit(2); }\nif (res.status === 404) { console.error(\"URL missing /rpc or wrong port\"); process.exit(2); }","typeGuard":"const isHttpLevelError = (err) => /HTTP \\d{3}$/.test(err?.message || \"\");","tryCatchPattern":"try {\n  return await rpc(coreUrl, token, method, params);\n} catch (err) {\n  if (/HTTP 401$/.test(err.message)) { token = await refreshToken(); return await rpc(coreUrl, token, method, params); }\n  throw err;\n}","preventionTips":["Treat 401 as a token-refresh signal: re-read <workspace>/core.token after any core restart","Scope env vars per invocation (env -u OPENHUMAN_CORE_TOKEN ...) to avoid invisible overrides","Prefer --spawn-core in throwaway runs; it removes token staleness entirely"],"tags":["rpc","http","auth","configuration"],"backgroundTag":null,"analyzedSha":"a221052e0df5b1f7598fceba7329fd1af95d6699","analyzedAt":"2026-08-16T12:47:06.542Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}