farion1231/cc-switch · error · Error

HTTP

Error message

HTTP ${response.status}

What it means

fetchModelsDevPricing fetches the models.dev pricing catalog with an AbortController-bounded timeout (MODELS_DEV_FETCH_TIMEOUT_MS) and throws 'HTTP <status>' whenever response.ok is false. The message intentionally carries only the status code; a timeout instead surfaces as an AbortError from fetch, not as this error. This is a transient server-side failure class: 5xx outages and 429 rate limits are the usual statuses.

Solutions

  1. Retry with exponential backoff (especially for 429/5xx) before giving up
  2. Cache the last successful ModelsDevResponse and serve it when the fetch fails
  3. Degrade gracefully — pricing is auxiliary data, so keep provider switching working without it

Example fix

// before
const data = await fetchModelsDevPricing(); // throws 'HTTP 503'

// after
let data: ModelsDevResponse | null = null;
for (let attempt = 0; attempt < 3 && !data; attempt++) {
  try {
    data = await fetchModelsDevPricing();
  } catch (error) {
    if (attempt === 2) {
      data = lastGoodCache; // fall back to last good copy
    } else {
      await delay(2 ** attempt * 500);
    }
  }
}
Defensive patterns

Strategy: retry

Try / catch

async function fetchPricingSafe(fallback: ModelsDevResponse | null): Promise<ModelsDevResponse | null> {
  for (let attempt = 0; attempt < 3; attempt++) {
    try {
      return await fetchModelsDevPricing();
    } catch (error) {
      const msg = error instanceof Error ? error.message : '';
      const retriable = msg.startsWith('HTTP 5') || msg === 'HTTP 429';
      if (!retriable || attempt === 2) return fallback; // degrade to cache/offline
      await new Promise((r) => setTimeout(r, 2 ** attempt * 500));
    }
  }
  return fallback;
}

Prevention

When it happens

Trigger: fetch(MODELS_DEV_API_URL) resolves with response.ok === false — e.g. models.dev returning 502/503 behind its CDN, or 429 when the client retries too aggressively.

Common situations: App startup while models.dev is degraded; CI/e2e runs hitting rate limits; corporate proxies returning 403 interstitial pages.

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 farion1231/cc-switch@0b5da51016 (2026-08-20). Data as JSON: /api/errors/952cdcf04f8c67a1. Report an issue: GitHub.

Appendix: source

Thrown at src/lib/modelsDevPricing.ts:152

    (a, b) =>
      b.releaseDate.localeCompare(a.releaseDate) ||
      a.modelName.localeCompare(b.modelName),
  );
  return entries;
}

export async function fetchModelsDevPricing(): Promise<ModelsDevResponse> {
  const controller = new AbortController();
  const timeout = window.setTimeout(
    () => controller.abort(),
    MODELS_DEV_FETCH_TIMEOUT_MS,
  );
  try {
    const response = await fetch(MODELS_DEV_API_URL, {
      signal: controller.signal,
    });
    if (!response.ok) {
      throw new Error(`HTTP ${response.status}`);
    }
    return (await response.json()) as ModelsDevResponse;
  } finally {
    window.clearTimeout(timeout);
  }
}

const COMMON_MODEL_LIMIT_PER_FAMILY = 6;

interface CommonFamilyRule {
  id: string;
  providers: ReadonlySet<string>;
  matches: (modelId: string) => boolean;
}

const COMMON_FAMILY_RULES: CommonFamilyRule[] = [
  {
    id: "claude",

View on GitHub (pinned to 0b5da51016)