{"record":{"id":"c8b168ba4b17c1eb","repo":"srbhr/Resume-Matcher","slug":"failed-to-fetch-system-status-status-res-status","errorCode":null,"errorMessage":"Failed to fetch system status (status ${res.status}).","messagePattern":"Failed to fetch system status \\(status (.+?)\\)\\.","errorType":"http","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"apps/frontend/lib/api/config.ts","lineNumber":145,"sourceCode":"    options.headers = { 'Content-Type': 'application/json' };\n    options.body = JSON.stringify(config);\n  }\n\n  const res = await apiFetch('/config/llm-test', options);\n\n  if (!res.ok) {\n    throw new Error(`Failed to test LLM connection (status ${res.status}).`);\n  }\n\n  return res.json();\n}\n\n// Fetch system status\nexport async function fetchSystemStatus(): Promise<SystemStatus> {\n  const res = await apiFetch('/status', { credentials: 'include' });\n\n  if (!res.ok) {\n    throw new Error(`Failed to fetch system status (status ${res.status}).`);\n  }\n\n  return res.json();\n}\n\n// Provider display names and default models\nexport const PROVIDER_INFO: Record<\n  LLMProvider,\n  {\n    name: string;\n    defaultModel: string;\n    requiresKey: boolean;\n    requiresBaseUrl?: boolean;\n    /**\n     * Base URL this provider owns. Used both to seed the field on switch-in\n     * and to decide whether to clear it on switch-out, so a previous\n     * provider's endpoint can't be persisted against the next one.\n     */","sourceCodeStart":127,"sourceCodeEnd":163,"githubUrl":"https://github.com/srbhr/Resume-Matcher/blob/116f9cc3b00e1ac91734a6c2679bf41ea64a0edc/apps/frontend/lib/api/config.ts#L127-L163","documentation":"fetchSystemStatus calls GET /status with credentials and throws this Error when the response is not ok. It is a thin wrapper — the response body with the actual failure reason is discarded.","triggerScenarios":"GET /status returns non-OK: backend down (network error handled separately), 401/403 auth required, 404 wrong API base path, 503 during backend restart or migration.","commonSituations":"Dashboard/status widget polling while the backend container is restarting; frontend pointed at the wrong port or a stale reverse-proxy route; session cookie expired causing 401.","solutions":["Check the status code: 5xx/503 -> inspect backend health and restart it if needed; 404 -> fix the API base URL; 401 -> re-login","Curl the backend /status endpoint directly to isolate frontend vs backend","Ensure frontend and backend versions match (route exists)","For status polling UIs, treat this as non-fatal and retry with backoff"],"exampleFix":"// before\nconst status = await fetchSystemStatus();\n// after\nconst status = await fetchSystemStatus().catch((e) => {\n  console.warn('status unavailable:', e.message);\n  return { online: false } as SystemStatus;\n});","handlingStrategy":"fallback","validationCode":"const API_BASE = process.env.NEXT_PUBLIC_API_BASE_URL;\nif (!API_BASE) console.warn('NEXT_PUBLIC_API_BASE_URL unset; /status calls may 404');","typeGuard":"function isStatusError(e: unknown): e is Error & { status?: number } {\n  const m = e instanceof Error ? e.message.match(/status (\\d{3})/) : null;\n  if (e instanceof Error && m) (e as any).status = Number(m[1]);\n  return e instanceof Error;\n}","tryCatchPattern":"let status: SystemStatus;\ntry {\n  status = await fetchSystemStatus();\n} catch {\n  status = { online: false } as SystemStatus; // render offline badge\n}","preventionTips":["Render an 'offline' state instead of crashing the dashboard when /status fails","Add a readiness probe on the backend and check it during deploys","Verify API base URL/proxy routing in CI smoke tests","Back off polling when the backend is down to avoid error spam"],"tags":["http","status","fetch","frontend"],"backgroundTag":"http-error-response","analyzedSha":"116f9cc3b00e1ac91734a6c2679bf41ea64a0edc","analyzedAt":"2026-08-28T22:51:40.999Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}