{"record":{"id":"e3cdfc26b1a4d392","repo":"paperclipai/paperclip","slug":"payload-error-failed-to-load-health-res","errorCode":null,"errorMessage":"${payload?.error ?? `Failed to load health (${res.status})`}","messagePattern":"\\$\\{payload\\?\\.error \\?\\? `Failed to load health \\(\\$\\{res\\.status\\}\\)`\\}","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"ui/src/api/health.ts","lineNumber":57,"sourceCode":"  cloud?: CloudInstanceHealthStatus;\n  /**\n   * Settings surfaces hidden by the hosting operator (keys from the shared\n   * settings-visibility registry). Absent when nothing is hidden.\n   */\n  hiddenSettings?: string[];\n};\n\nexport const healthApi = {\n  get: async (): Promise<HealthStatus> => {\n    const res = await fetch(\"/api/health\", {\n      credentials: \"include\",\n      headers: { Accept: \"application/json\" },\n    });\n    if (!res.ok) {\n      const payload = await res.json().catch(() => null) as { error?: string } | null;\n      const recovery = tenantSessionRecovery.recoverIfNeeded(res.status, payload);\n      if (recovery) return recovery;\n      throw new Error(payload?.error ?? `Failed to load health (${res.status})`);\n    }\n    return res.json();\n  },\n  requestDevServerRestart: async (): Promise<void> => {\n    const res = await fetch(\"/api/health/dev-server/restart\", {\n      method: \"POST\",\n      credentials: \"include\",\n      headers: { Accept: \"application/json\" },\n    });\n    if (!res.ok) {\n      const payload = await res.json().catch(() => null) as { error?: string } | null;\n      const recovery = tenantSessionRecovery.recoverIfNeeded(res.status, payload);\n      if (recovery) return recovery;\n      throw new Error(payload?.error ?? `Failed to request restart (${res.status})`);\n    }\n  },\n};\n","sourceCodeStart":39,"sourceCodeEnd":75,"githubUrl":"https://github.com/paperclipai/paperclip/blob/01ad8584922b5d85292b1723cae71fa0d9b07a19/ui/src/api/health.ts#L39-L75","documentation":"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.","triggerScenarios":"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.","commonSituations":"API server overloaded or restarting, dev server crash loop, database unreachable causing /api/health to return 500, corporate proxy intercepting the request.","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"],"exampleFix":"// before\nthrow new Error(payload?.error ?? `Failed to load health (${res.status})`);\n// after\nif (res.status >= 500) { await sleep(1000); return getHealth(); }\nthrow new Error(payload?.error ?? `Failed to load health (${res.status})`);","handlingStrategy":"retry","validationCode":"const reachable = await fetch('/api/health', { method: 'HEAD' }).then(r => r.ok).catch(() => false);","typeGuard":"function isHealthError(p: unknown): p is { error: string } { return typeof p === 'object' && p !== null && typeof (p as any).error === 'string'; }","tryCatchPattern":"try { const h = await healthApi.get(); } catch (e) { if (/Failed to load health/.test(e.message)) { scheduleRetry(3); } else showToast(e.message); }","preventionTips":["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"],"tags":["http","health-check","api"],"backgroundTag":"http-error-response","analyzedSha":"01ad8584922b5d85292b1723cae71fa0d9b07a19","analyzedAt":"2026-09-10T03:14:50.855Z","contentChangedAt":"2026-09-10T03:14:50.855Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}