srbhr/Resume-Matcher · error · Error

Failed to load feature config (status ${res.status}).

Error message

Failed to load feature config (status ${res.status}).

What it means

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.

Source

Thrown at apps/frontend/lib/api/config.ts:226

// Feature configuration types
export interface FeatureConfig {
  enable_cover_letter: boolean;
  enable_outreach_message: boolean;
  enable_interview_prep: boolean;
}

export interface FeatureConfigUpdate {
  enable_cover_letter?: boolean;
  enable_outreach_message?: boolean;
  enable_interview_prep?: boolean;
}

// Fetch feature configuration
export async function fetchFeatureConfig(): Promise<FeatureConfig> {
  const res = await apiFetch('/config/features', { credentials: 'include' });

  if (!res.ok) {
    throw new Error(`Failed to load feature config (status ${res.status}).`);
  }

  return res.json();
}

// Update feature configuration
export async function updateFeatureConfig(config: FeatureConfigUpdate): Promise<FeatureConfig> {
  const res = await apiFetch('/config/features', {
    method: 'PUT',
    headers: { 'Content-Type': 'application/json' },
    credentials: 'include',
    body: JSON.stringify(config),
  });

  if (!res.ok) {
    const data = await res.json().catch(() => ({}));
    throw new Error(data.detail || `Failed to update feature config (status ${res.status}).`);
  }

View on GitHub (pinned to 116f9cc3b0)

Solutions

  1. Re-login if status is 401/403; the call uses credentials: 'include' and needs a valid session
  2. Confirm the deployed backend exposes GET /config/features (404)
  3. Check backend logs for 500 causes (storage/migration)
  4. Verify API base URL / proxy routing between frontend and backend

Example fix

// before
const fc = await fetchFeatureConfig();
// after
const fc = await fetchFeatureConfig().catch((e) => {
  if (e.message.includes('status 401')) redirect('/login');
  return DEFAULT_FEATURE_CONFIG;
});
Defensive patterns

Strategy: fallback

Validate before calling

const sessionOk = document.cookie.includes('session');
if (!sessionOk) await ensureLogin(); // before GET /config/features

Type guard

function isFeatureConfigError(e: unknown): e is Error & { status?: number } {
  const m = e instanceof Error ? e.message.match(/status (\d{3})/) : null;
  if (e instanceof Error && m) (e as any).status = Number(m[1]);
  return e instanceof Error;
}

Try / catch

let featureConfig: FeatureConfig;
try {
  featureConfig = await fetchFeatureConfig();
} catch (e) {
  if ((e as any)?.status === 401) redirect('/login');
  featureConfig = DEFAULT_FEATURE_CONFIG;
}

Prevention

When it happens

Trigger: GET /config/features returns non-OK: 401 unauthenticated session, 404 backend lacking the route (version mismatch), 500 backend feature-store read failure.

Common situations: 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.

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 srbhr/Resume-Matcher@116f9cc3b0 (2026-08-28). Data as JSON: /api/errors/08341fb2be0be70f. Report an issue: GitHub.