{"record":{"id":"76943037124b6146","repo":"tinyhumansai/openhuman","slug":"core-rpc-http-response-status-text-respon","errorCode":null,"errorMessage":"Core RPC HTTP ${response.status}: ${text || response.statusText}","messagePattern":"Core RPC HTTP (.+?): (.+?)","errorType":"http","errorClass":"CoreRpcError","httpStatus":null,"severity":"error","filePath":"app/src/services/coreRpcClient.ts","lineNumber":745,"sourceCode":"          `Core RPC ${payload.method} timed out after ${effectiveTimeoutMs}ms`,\n          'timeout'\n        );\n      }\n      throw fetchErr;\n    } finally {\n      clearTimeout(timeoutId);\n    }\n\n    if (!response.ok) {\n      const text = await response.text();\n      const httpMessage = `Core RPC HTTP ${response.status}: ${text || response.statusText}`;\n      const kind = classifyRpcError(text || response.statusText, response.status);\n      if (kind === 'auth_expired' && !suppressAuthExpiredEvent)\n        dispatchAuthExpired(\n          payload.method,\n          classifyAuthExpiredReason(text || response.statusText, response.status)\n        );\n      throw new CoreRpcError(httpMessage, kind, response.status);\n    }\n\n    const json = (await response.json()) as JsonRpcResponse<T>;\n\n    if (json.error) {\n      coreRpcError('HTTP error response', {\n        id: payload.id,\n        method: payload.method,\n        error: json.error,\n      });\n      const rawMessage = json.error.message || 'Core RPC returned an error';\n      const kind = classifyRpcError(rawMessage, undefined, json.error.data);\n      if (kind === 'auth_expired' && !suppressAuthExpiredEvent)\n        dispatchAuthExpired(payload.method, classifyAuthExpiredReason(rawMessage, undefined));\n      throw new CoreRpcError(rawMessage, kind, undefined, json.error.data);\n    }\n    if (!Object.prototype.hasOwnProperty.call(json, 'result')) {\n      throw new Error('Core RPC response missing result');","sourceCodeStart":727,"sourceCodeEnd":763,"githubUrl":"https://github.com/tinyhumansai/openhuman/blob/a221052e0df5b1f7598fceba7329fd1af95d6699/app/src/services/coreRpcClient.ts#L727-L763","documentation":"Thrown by callCoreRpc when the core's /rpc endpoint answers HTTP non-2xx: the body text is read, classifyRpcError maps it to a kind (401 -> auth_expired, which also dispatches the auth-expired event unless suppressed; 429 -> rate_limited; etc.), and a CoreRpcError carrying kind and the HTTP status is thrown. The message embeds the status plus the body text or statusText.","triggerScenarios":"401 with a stale bearer (core restarted and minted a new token while the client cached the old one); 404 from pointing at the wrong port/path; 500/503 when the core process is crashing or its HTTP layer is wedged; any proxy in front of /rpc answering with an error status.","commonSituations":"Token staleness across core restarts (restartCoreProcess clears the token cache for exactly this reason); misconfigured rpcUrl (leftover port from a previous launch); core panic during a request; rate limiting through a relayed/tunneled transport.","solutions":["Branch on the status: 401 -> let the auth-expired flow run (it clears/re-fetches the token; clearCoreRpcTokenCache exists for restarts); 429 -> back off; 5xx -> restart the core and retry","Verify the rpcUrl points at the live core (GET /health and GET /schema on the same origin)","Check core logs at the request timestamp for panics/errors behind a 500","If it follows a core restart, ensure nothing bypasses the token-cache clearing path"],"exampleFix":"// before\nawait callCoreRpc({ method: 'openhuman.flows_list' });\n\n// after\ntry {\n  await callCoreRpc({ method: 'openhuman.flows_list' });\n} catch (e) {\n  if (e instanceof CoreRpcError && e.kind === 'auth_expired') {\n    await clearCoreRpcTokenCache();\n    return callCoreRpc({ method: 'openhuman.flows_list' }); // retry with fresh token\n  }\n  throw e;\n}","handlingStrategy":"try-catch","validationCode":"// Health-check the endpoint before a burst of RPCs (e.g. after a core restart)\nconst ok = await fetch(`${rpcBaseUrl}/health`).then(r => r.ok).catch(() => false);\nif (!ok) await waitForCoreHealthy();","typeGuard":"import { CoreRpcError } from '../services/coreRpcClient';\nfunction isAuthExpired(e: unknown): e is CoreRpcError & { status?: number } {\n  return e instanceof CoreRpcError && e.kind === 'auth_expired';\n}","tryCatchPattern":"try {\n  return await callCoreRpc(payload);\n} catch (e) {\n  if (isAuthExpired(e)) {\n    clearCoreRpcTokenCache();\n    return callCoreRpc(payload); // re-fetch token once, then surface if it repeats\n  }\n  if (e instanceof CoreRpcError && e.status === 429) { await delay(2000); return callCoreRpc(payload); }\n  throw e;\n}","preventionTips":["After any core restart, drop the cached bearer before the next RPC (restartCoreProcess shows the pattern)","Verify rpcUrl/health when 404s appear — stale ports from previous launches are a classic cause","Inspect err.kind and err.status rather than string-matching the message"],"tags":["rpc","http","auth","core","status-code"],"backgroundTag":null,"analyzedSha":"a221052e0df5b1f7598fceba7329fd1af95d6699","analyzedAt":"2026-08-16T12:47:06.542Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}