{"record":{"id":"8f53956bb3b10c9c","repo":"tinyhumansai/openhuman","slug":"resolve-failed","errorCode":"RESOLVE_FAILED","errorMessage":"${reason}","messagePattern":"\\$\\{reason\\}","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"app/src/services/artifactDownloadService.ts","lineNumber":203,"sourceCode":"async function resolveArtifactForExport(\n  artifactId: string,\n  fallbackTitle: string,\n  extension: string\n): Promise<ResolveExportResult> {\n  if (!artifactId.trim()) {\n    return { ok: false, code: 'MISSING_ARTIFACT_ID', error: 'artifact id missing' };\n  }\n\n  let resolved: AiGetArtifactData;\n  try {\n    const raw = await callCoreRpc<AiGetArtifactData>({\n      method: 'openhuman.ai_get_artifact',\n      params: { artifact_id: artifactId },\n    });\n    resolved = raw ?? {};\n  } catch (err) {\n    const reason = err instanceof Error ? err.message : String(err);\n    return { ok: false, code: 'RESOLVE_FAILED', error: reason };\n  }\n\n  const sourcePath = resolved.absolute_path;\n  if (!sourcePath) {\n    return {\n      ok: false,\n      code: 'MISSING_ARTIFACT_PATH',\n      error: 'artifact path missing from core response',\n    };\n  }\n\n  // Prefer the persisted title (came from create_artifact's\n  // sanitized stem) but fall back to the caller-supplied hint.\n  const title = resolved.meta?.title?.trim() || fallbackTitle.trim() || 'artifact';\n  const ext = extension.trim().replace(/^\\.+/, '');\n  // Guard against double extensions: if `title` already ends in the\n  // requested extension (case-insensitive, with any other extension also\n  // tolerated), don't append again. Prevents `deck.pptx.pptx` when the","sourceCodeStart":185,"sourceCodeEnd":221,"githubUrl":"https://github.com/tinyhumansai/openhuman/blob/749120085864ce16e0f273c7b86fac7740b39c5b/app/src/services/artifactDownloadService.ts#L185-L221","documentation":"resolveArtifactForExport calls callCoreRpc('openhuman.ai_get_artifact', { artifact_id }); if that RPC rejects - JSON-RPC error from the core (unknown artifact id, method error), transport failure, or the embedded core not yet ready - the rejection's message is captured verbatim as reason and returned as { ok: false, code: 'RESOLVE_FAILED', error: reason }. Like MISSING_ARTIFACT_ID this is a returned outcome, not a thrown exception.","triggerScenarios":"The artifact id does not exist core-side (deleted or from another workspace); the embedded core process is still starting or has died so relay_http_rpc fails; the RPC returns a JSON-RPC error object whose message becomes the reason string.","commonSituations":"Downloading an artifact right as a thread switches or the core restarts; artifact ids persisted from an older workspace; any core-side regression in ai_get_artifact surfacing as this generic wrapper with the core's message inside.","solutions":["Read the embedded reason - it is the core RPC's own error message and distinguishes 'unknown artifact' from transport failures","Verify the artifact still exists (re-render the owning message / list) before exporting","For core-not-ready cases, retry once the core health check passes","Check core logs for the ai_get_artifact handler if the reason is opaque"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":"const isResolveFailed = (o: DownloadArtifactOutcome): o is { ok: false; code: 'RESOLVE_FAILED'; error: string } =>\n  !o.ok && o.code === 'RESOLVE_FAILED';","tryCatchPattern":"const outcome = await downloadArtifact(artifactId, title, ext);\nif (!outcome.ok) {\n  switch (outcome.code) {\n    case 'RESOLVE_FAILED':\n      // outcome.error is the core RPC's own message - show it, retry once if core was mid-start\n      showError(outcome.error);\n      break;\n    default:\n      showError(outcome.error);\n  }\n}","preventionTips":["Check core health before export flows if the core is freshly started","Log outcome.error verbatim - it carries the JSON-RPC reason and is the only detail you get","Remember resolve failures are returned, not thrown: branch on ok/code rather than wrapping in try/catch"],"tags":["artifacts","core-rpc","download","result-object","json-rpc"],"backgroundTag":"json-rpc-method-failed","analyzedSha":"749120085864ce16e0f273c7b86fac7740b39c5b","analyzedAt":"2026-08-17T21:21:45.363Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}