{"record":{"id":"0a60992b3e4a92f5","repo":"tinyhumansai/openhuman","slug":"core-returned-an-empty-backend-url","errorCode":null,"errorMessage":"Core returned an empty backend URL","messagePattern":"Core returned an empty backend URL","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"app/src/services/backendUrl.ts","lineNumber":63,"sourceCode":"  }\n\n  if (!coreIsTauri()) {\n    resolvedBackendUrl = webFallbackBackendUrl();\n    return resolvedBackendUrl;\n  }\n\n  if (resolvingBackendUrl) {\n    return resolvingBackendUrl;\n  }\n\n  const generation = backendUrlGeneration;\n  resolvingBackendUrl = (async () => {\n    const response = await callCoreRpc<{ api_url?: string; apiUrl?: string }>({\n      method: 'openhuman.config_resolve_api_url',\n    });\n    const resolved = String(response.api_url ?? response.apiUrl ?? '').trim();\n    if (!resolved) {\n      throw new Error('Core returned an empty backend URL');\n    }\n    const normalized = normalizeBaseUrl(resolved);\n    if (generation === backendUrlGeneration) {\n      resolvedBackendUrl = normalized;\n    }\n    return normalized;\n  })().finally(() => {\n    if (generation === backendUrlGeneration) {\n      resolvingBackendUrl = null;\n    }\n  });\n\n  return resolvingBackendUrl;\n}\n","sourceCodeStart":45,"sourceCodeEnd":78,"githubUrl":"https://github.com/tinyhumansai/openhuman/blob/a221052e0df5b1f7598fceba7329fd1af95d6699/app/src/services/backendUrl.ts#L45-L78","documentation":"Thrown by the backend-URL resolver when the 'openhuman.config_resolve_api_url' RPC succeeds but both candidate fields (api_url / apiUrl) resolve to an empty or whitespace-only string after trim. Every cloud-backend call needs this URL, so the resolver fails loudly instead of letting callers build requests against ''.","triggerScenarios":"Fresh workspace where config.toml has no backend/api URL set and no env override (e.g. OPENHUMAN_BACKEND_API_URL) is present; a config file with backend_api_url = \"\" ; the core's resolve handler answering with an empty string because neither config nor default was initialized yet.","commonSituations":"First run before onboarding sets the backend; self-hosted/custom-backend deployments that intentionally clear the cloud URL; core config migration wiping the value; testing against a core whose config was never initialized (config init not yet complete when resolve ran).","solutions":["Set the backend API URL: Settings in the app, or the backend URL key in the core config, or the documented env var in .env (see .env.example)","Confirm the core finished config initialization before the resolver runs (restart the app if it raced first-launch init)","Read back the raw value: call openhuman.config_resolve_api_url on /rpc and check the api_url field","If running self-hosted without the cloud, avoid code paths that resolve the backend URL (they are cloud-only)"],"exampleFix":"# .env (before: missing)\n# .env (after)\nOPENHUMAN_BACKEND_API_URL=https://api.example.com","handlingStrategy":"try-catch","validationCode":"// Check that a backend URL is configured before entering cloud-dependent flows\nconst hasBackend = await callCoreRpc<{ api_url?: string }>({ method: 'openhuman.config_resolve_api_url' })\n  .then(r => Boolean((r.api_url ?? '').trim()))\n  .catch(() => false);\nif (!hasBackend) blockCloudFeatures('Set the backend API URL in Settings first.');","typeGuard":"function isResolvedBackendUrl(v: unknown): v is { api_url: string } {\n  const r = v as Record<string, unknown> | null | undefined;\n  return !!r && typeof r.api_url === 'string' && r.api_url.trim().length > 0;\n}","tryCatchPattern":"try {\n  const base = await resolveBackendUrl();\n} catch (e) {\n  if (e instanceof Error && e.message.includes('empty backend URL')) {\n    promptUserToConfigureBackend(); // Settings / env — then retry resolution\n  } else throw e;\n}","preventionTips":["Set the backend URL during onboarding before any cloud call can fire","Keep the env override (.env / OPENHUMAN_BACKEND_API_URL) documented in .env.example","Gate cloud-only features on a resolved URL so the error never surfaces mid-flow"],"tags":["config","rpc","backend-url","setup"],"backgroundTag":null,"analyzedSha":"a221052e0df5b1f7598fceba7329fd1af95d6699","analyzedAt":"2026-08-16T12:47:06.542Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}