tinyhumansai/openhuman · error

Core returned an empty backend URL

Error message

Core returned an empty backend URL

What it means

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 ''.

Source

Thrown at app/src/services/backendUrl.ts:63

  }

  if (!coreIsTauri()) {
    resolvedBackendUrl = webFallbackBackendUrl();
    return resolvedBackendUrl;
  }

  if (resolvingBackendUrl) {
    return resolvingBackendUrl;
  }

  const generation = backendUrlGeneration;
  resolvingBackendUrl = (async () => {
    const response = await callCoreRpc<{ api_url?: string; apiUrl?: string }>({
      method: 'openhuman.config_resolve_api_url',
    });
    const resolved = String(response.api_url ?? response.apiUrl ?? '').trim();
    if (!resolved) {
      throw new Error('Core returned an empty backend URL');
    }
    const normalized = normalizeBaseUrl(resolved);
    if (generation === backendUrlGeneration) {
      resolvedBackendUrl = normalized;
    }
    return normalized;
  })().finally(() => {
    if (generation === backendUrlGeneration) {
      resolvingBackendUrl = null;
    }
  });

  return resolvingBackendUrl;
}

View on GitHub (pinned to a221052e0d)

Solutions

  1. 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)
  2. Confirm the core finished config initialization before the resolver runs (restart the app if it raced first-launch init)
  3. Read back the raw value: call openhuman.config_resolve_api_url on /rpc and check the api_url field
  4. If running self-hosted without the cloud, avoid code paths that resolve the backend URL (they are cloud-only)

Example fix

# .env (before: missing)
# .env (after)
OPENHUMAN_BACKEND_API_URL=https://api.example.com
Defensive patterns

Strategy: try-catch

Validate before calling

// Check that a backend URL is configured before entering cloud-dependent flows
const hasBackend = await callCoreRpc<{ api_url?: string }>({ method: 'openhuman.config_resolve_api_url' })
  .then(r => Boolean((r.api_url ?? '').trim()))
  .catch(() => false);
if (!hasBackend) blockCloudFeatures('Set the backend API URL in Settings first.');

Type guard

function isResolvedBackendUrl(v: unknown): v is { api_url: string } {
  const r = v as Record<string, unknown> | null | undefined;
  return !!r && typeof r.api_url === 'string' && r.api_url.trim().length > 0;
}

Try / catch

try {
  const base = await resolveBackendUrl();
} catch (e) {
  if (e instanceof Error && e.message.includes('empty backend URL')) {
    promptUserToConfigureBackend(); // Settings / env — then retry resolution
  } else throw e;
}

Prevention

When it happens

Trigger: 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.

Common situations: 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).

Related errors


AI-assisted analysis of tinyhumansai/openhuman@a221052e0d (2026-08-16). Data as JSON: /api/errors/0a60992b3e4a92f5. Report an issue: GitHub.