{"record":{"id":"08341fb2be0be70f","repo":"srbhr/Resume-Matcher","slug":"failed-to-load-feature-config-status-res-status","errorCode":null,"errorMessage":"Failed to load feature config (status ${res.status}).","messagePattern":"Failed to load feature config \\(status (.+?)\\)\\.","errorType":"http","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"apps/frontend/lib/api/config.ts","lineNumber":226,"sourceCode":"// Feature configuration types\nexport interface FeatureConfig {\n  enable_cover_letter: boolean;\n  enable_outreach_message: boolean;\n  enable_interview_prep: boolean;\n}\n\nexport interface FeatureConfigUpdate {\n  enable_cover_letter?: boolean;\n  enable_outreach_message?: boolean;\n  enable_interview_prep?: boolean;\n}\n\n// Fetch feature configuration\nexport async function fetchFeatureConfig(): Promise<FeatureConfig> {\n  const res = await apiFetch('/config/features', { credentials: 'include' });\n\n  if (!res.ok) {\n    throw new Error(`Failed to load feature config (status ${res.status}).`);\n  }\n\n  return res.json();\n}\n\n// Update feature configuration\nexport async function updateFeatureConfig(config: FeatureConfigUpdate): Promise<FeatureConfig> {\n  const res = await apiFetch('/config/features', {\n    method: 'PUT',\n    headers: { 'Content-Type': 'application/json' },\n    credentials: 'include',\n    body: JSON.stringify(config),\n  });\n\n  if (!res.ok) {\n    const data = await res.json().catch(() => ({}));\n    throw new Error(data.detail || `Failed to update feature config (status ${res.status}).`);\n  }","sourceCodeStart":208,"sourceCodeEnd":244,"githubUrl":"https://github.com/srbhr/Resume-Matcher/blob/116f9cc3b00e1ac91734a6c2679bf41ea64a0edc/apps/frontend/lib/api/config.ts#L208-L244","documentation":"fetchFeatureConfig calls GET /config/features with credentials and throws this Error on any non-OK response. It is called during settings-page load, so a failure here breaks the feature-flags panel initialization.","triggerScenarios":"GET /config/features returns non-OK: 401 unauthenticated session, 404 backend lacking the route (version mismatch), 500 backend feature-store read failure.","commonSituations":"Loading the settings page with an expired cookie; deploying a new frontend against an older backend (or vice versa) so /config/features does not exist; database unavailable on the backend.","solutions":["Re-login if status is 401/403; the call uses credentials: 'include' and needs a valid session","Confirm the deployed backend exposes GET /config/features (404)","Check backend logs for 500 causes (storage/migration)","Verify API base URL / proxy routing between frontend and backend"],"exampleFix":"// before\nconst fc = await fetchFeatureConfig();\n// after\nconst fc = await fetchFeatureConfig().catch((e) => {\n  if (e.message.includes('status 401')) redirect('/login');\n  return DEFAULT_FEATURE_CONFIG;\n});","handlingStrategy":"fallback","validationCode":"const sessionOk = document.cookie.includes('session');\nif (!sessionOk) await ensureLogin(); // before GET /config/features","typeGuard":"function isFeatureConfigError(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 featureConfig: FeatureConfig;\ntry {\n  featureConfig = await fetchFeatureConfig();\n} catch (e) {\n  if ((e as any)?.status === 401) redirect('/login');\n  featureConfig = DEFAULT_FEATURE_CONFIG;\n}","preventionTips":["Ship frontend and backend together so /config/features always exists","Keep DEFAULT_FEATURE_CONFIG in sync with backend defaults","Re-authenticate before config fetches after long idle","Include /config/features in deployment smoke tests"],"tags":["http","config","feature-flags","frontend"],"backgroundTag":"http-error-response","analyzedSha":"116f9cc3b00e1ac91734a6c2679bf41ea64a0edc","analyzedAt":"2026-08-28T22:51:40.999Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}