{"record":{"id":"480dcc91bc95bab0","repo":"tinyhumansai/openhuman","slug":"core-rpc-returned-an-error","errorCode":null,"errorMessage":"Core RPC returned an error","messagePattern":"Core RPC returned an error","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"app/src/services/api/providerSurfacesApi.ts","lineNumber":18,"sourceCode":"import type { RespondQueueList } from '../../types/providerSurfaces';\nimport { callCoreRpc } from '../coreRpcClient';\n\ninterface ProviderSurfacesQueueEnvelope {\n  data?: RespondQueueList;\n  result?: { data?: RespondQueueList };\n}\n\nconst EMPTY_QUEUE: RespondQueueList = { items: [], count: 0 };\n\nfunction parseQueueEnvelope(raw: unknown): RespondQueueList {\n  if (!raw || typeof raw !== 'object') {\n    throw new Error('provider_surfaces_list_queue: unexpected empty response');\n  }\n\n  const envelope = raw as ProviderSurfacesQueueEnvelope & { error?: { message?: string } };\n  if (envelope.error) {\n    throw new Error(envelope.error.message ?? 'Core RPC returned an error');\n  }\n  const candidate = envelope.result?.data ?? envelope.data;\n  if (!candidate || !Array.isArray(candidate.items) || typeof candidate.count !== 'number') {\n    return EMPTY_QUEUE;\n  }\n  return candidate;\n}\n\nexport const providerSurfacesApi = {\n  async listQueue(): Promise<RespondQueueList> {\n    const raw = await callCoreRpc<unknown>({ method: 'openhuman.provider_surfaces_list_queue' });\n    return parseQueueEnvelope(raw);\n  },\n};\n","sourceCodeStart":1,"sourceCodeEnd":33,"githubUrl":"https://github.com/tinyhumansai/openhuman/blob/749120085864ce16e0f273c7b86fac7740b39c5b/app/src/services/api/providerSurfacesApi.ts#L1-L33","documentation":"Thrown by parseQueueEnvelope() when the raw RPC response carries an `error` object but that error has no `message` string — this literal is the fallback. The core (or the RPC transport) reported a failure for provider_surfaces_list_queue, but the error details were lost or the error was an empty object, so the UI substitutes a generic message. The real cause lives in the core's logs.","triggerScenarios":"The core handler returned a JSON-RPC error with a non-string or missing message field; the Tauri relay wrapped a core-side panic/timeout as {error:{}}; an envelope from an older core shape where error details ride a different key (code/description).","commonSituations":"Core crashed or timed out serving the queue list; version skew changing the error envelope shape; provider-surfaces store not initialized at boot so the handler errors early with a bare error.","solutions":["Check the core logs around the request — the concrete failure reason is only visible there.","Restart the core; a failed store init or transient lock often clears on a fresh boot.","If the error envelope is from an older core, update core+app together to align the error shape.","Improve the fallback to include envelope.error.code/stringified error so users see more than the generic text."],"exampleFix":"// before\nif (envelope.error) {\n  throw new Error(envelope.error.message ?? 'Core RPC returned an error');\n}\n\n// after — preserve whatever detail the envelope carried\nif (envelope.error) {\n  const detail = envelope.error.message ?? envelope.error.code ?? JSON.stringify(envelope.error);\n  throw new Error(`provider_surfaces_list_queue failed: ${detail}`);\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":"function hasErrorMessage(e: unknown): e is { error: { message: string } } {\n  return typeof (e as { error?: { message?: unknown } } | null)?.error?.message === 'string';\n}","tryCatchPattern":"try {\n  return await providerSurfacesApi.listQueue();\n} catch (e) {\n  const msg = e instanceof Error ? e.message : String(e);\n  if (msg === 'Core RPC returned an error') {\n    // detail was lost — check core logs; retry once after a core health check\n    await waitForCoreHealthy();\n    return await providerSurfacesApi.listQueue();\n  }\n  throw e;\n}","preventionTips":["When wrapping envelopes, propagate error.code/description so the generic fallback rarely fires.","Correlate with core logs using a request id when this surfaces in Sentry.","Retry once after confirming core health — transient store init failures clear on restart."],"tags":["core-rpc","rpc-error-envelope","provider-surfaces","error-message-lost"],"backgroundTag":"rpc-error-envelope","analyzedSha":"749120085864ce16e0f273c7b86fac7740b39c5b","analyzedAt":"2026-08-17T21:21:45.363Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}