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
- Check the API server logs for the underlying health failure
- If 503 during a restart, add retry/backoff before surfacing
- Verify the dev server process is up (pnpm dev) and port 3100 is correct
- 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
- Poll health with exponential backoff instead of failing immediately
- Treat 5xx health as transient; 4xx as configuration error
- Keep the health endpoint dependency-free so it rarely 500s
- Verify dev server is running before rendering health-dependent UI
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
- OpenCode API ${path} request failed: ${redact(String(error),
- OpenCode API ${path} returned HTTP ${response.status}: ${red
- Discord ${operation} failed (HTTP ${response.status}${code ?
- ${(payload as { error?: string } | null)?.error ?? `Failed t
- ${(errorBody as { error?: string } | null)?.error ?? `Reques
AI-assisted analysis of paperclipai/paperclip@01ad858492 (2026-09-10).
Data as JSON: /api/errors/e3cdfc26b1a4d392.
Report an issue: GitHub.