paperclipai/paperclip · error

${payload?.error ?? `Failed to load health (${res.status})`}

Error message

${payload?.error ?? `Failed to load health (${res.status})`}

What it means

The health API's status loader throws this Error when the health endpoint responds non-OK. It uses the server's `error` field if present, otherwise a generic message embedding the status code. Tenant session recovery is consulted before throwing.

Source

Thrown at ui/src/api/health.ts:57

  cloud?: CloudInstanceHealthStatus;
  /**
   * Settings surfaces hidden by the hosting operator (keys from the shared
   * settings-visibility registry). Absent when nothing is hidden.
   */
  hiddenSettings?: string[];
};

export const healthApi = {
  get: async (): Promise<HealthStatus> => {
    const res = await fetch("/api/health", {
      credentials: "include",
      headers: { Accept: "application/json" },
    });
    if (!res.ok) {
      const payload = await res.json().catch(() => null) as { error?: string } | null;
      const recovery = tenantSessionRecovery.recoverIfNeeded(res.status, payload);
      if (recovery) return recovery;
      throw new Error(payload?.error ?? `Failed to load health (${res.status})`);
    }
    return res.json();
  },
  requestDevServerRestart: async (): Promise<void> => {
    const res = await fetch("/api/health/dev-server/restart", {
      method: "POST",
      credentials: "include",
      headers: { Accept: "application/json" },
    });
    if (!res.ok) {
      const payload = await res.json().catch(() => null) as { error?: string } | null;
      const recovery = tenantSessionRecovery.recoverIfNeeded(res.status, payload);
      if (recovery) return recovery;
      throw new Error(payload?.error ?? `Failed to request restart (${res.status})`);
    }
  },
};

View on GitHub (pinned to 01ad858492)

Solutions

  1. Check the API server logs for the underlying health failure
  2. If 503 during a restart, add retry/backoff before surfacing
  3. Verify the dev server process is up (pnpm dev) and port 3100 is correct
  4. Check proxy config is not stripping JSON error bodies

Example fix

// before
throw new Error(payload?.error ?? `Failed to load health (${res.status})`);
// after
if (res.status >= 500) { await sleep(1000); return getHealth(); }
throw new Error(payload?.error ?? `Failed to load health (${res.status})`);
Defensive patterns

Strategy: retry

Validate before calling

const reachable = await fetch('/api/health', { method: 'HEAD' }).then(r => r.ok).catch(() => false);

Type guard

function isHealthError(p: unknown): p is { error: string } { return typeof p === 'object' && p !== null && typeof (p as any).error === 'string'; }

Try / catch

try { const h = await healthApi.get(); } catch (e) { if (/Failed to load health/.test(e.message)) { scheduleRetry(3); } else showToast(e.message); }

Prevention

When it happens

Trigger: GET health endpoint returns 5xx or 503 while the server is degraded; proxy returns non-JSON error page so payload is null; recovery interceptor fails to recover.

Common situations: API server overloaded or restarting, dev server crash loop, database unreachable causing /api/health to return 500, corporate proxy intercepting the request.

Understand the failure class

Background: "API error: {status}" and "HTTP 401/403/404/429/5xx" errors: non-2xx HTTP responses explained — this error's family across 27 libraries.

Related errors


AI-assisted analysis of paperclipai/paperclip@01ad858492 (2026-09-10). Data as JSON: /api/errors/e3cdfc26b1a4d392. Report an issue: GitHub.