janhq/jan · error

Failed to fetch models from

Error message

Failed to fetch models from ${provider.provider}: ${result.status} ${result.statusText}

What it means

After exhausting key rotation attempts, fetchTopRemoteModels throws with the provider name and the last HTTP status/statusText when the models-list response was not ok. Statuses 401/403/429 trigger a retry with the next key; any other non-ok status (or being on the last attempt) throws immediately. It wraps the upstream HTTP failure with provider context.

Solutions

  1. Check the status code in the message: 404 means fix base_url to include the correct API path (usually /v1).
  2. For 401/403/429, replace or wait out the API keys and retry.
  3. For 5xx, verify provider status/retry with backoff; confirm the endpoint is OpenAI-compatible and serves GET /models.

Example fix

// before
provider.base_url = 'https://api.openai.com' // 404: no /models here
// after
provider.base_url = 'https://api.openai.com/v1'
Defensive patterns

Strategy: retry

Validate before calling

const probe = await fetch(`${provider.base_url.replace(/\/$/, '')}/models`, { headers: buildHeaders(provider) })
if (!probe.ok) console.warn('catalog endpoint returned', probe.status)

Type guard

const isRetryableStatus = (s) => [401, 403, 429, 500, 502, 503, 504].includes(s)

Try / catch

try { models = await fetchTopRemoteModels(provider, fetch) } catch (e) { if (/Failed to fetch models from/.test(e.message)) { const status = parseInt(e.message.match(/(\d{3})/)?.[1] ?? '0', 10); if (isRetryableStatus(status)) await backoffRetry(); else showErrorWithStatusHint(status) } }

Prevention

When it happens

Trigger: Provider returns 404 (wrong base_url path, missing /v1), 500/502 upstream outage, 400 bad request, or 401/403/429 on the final key attempt; endpoint not actually OpenAI-compatible (no /models route).

Common situations: base_url pointing at a server without a models endpoint; provider outage or gateway error; all keys rate-limited simultaneously; wrong path like https://api.openai.com (missing /v1).

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 janhq/jan@7205d770c1 (2026-09-17). Data as JSON: /api/errors/426298b62b10ed9f. Report an issue: GitHub.

Appendix: source

Thrown at web-app/src/lib/remoteModelCatalog.ts:223

    throw new Error('Provider must have base_url configured')
  }

  const keyChain = providerRemoteApiKeyChain(provider)
  const attempts: (string | undefined)[] = keyChain.length > 0 ? keyChain : [undefined]

  let lastStatus = 0
  let lastStatusText = ''
  for (let i = 0; i < attempts.length; i++) {
    const result = await getJson(
      fetchImpl,
      `${provider.base_url}/models`,
      buildHeaders(provider, attempts[i])
    )
    lastStatus = result.status
    lastStatusText = result.statusText
    if (!result.ok) {
      if ([401, 403, 429].includes(result.status) && i < attempts.length - 1) continue
      throw new Error(`Failed to fetch models from ${provider.provider}: ${result.status} ${result.statusText}`)
    }

    const body = result.body as { data?: unknown }
    const rows = Array.isArray(body?.data) ? (body.data as unknown[]) : []
    return normalizeCatalog(kind, rows)
  }

  throw new Error(`Failed to fetch models from ${provider.provider}: ${lastStatus} ${lastStatusText}`)
}

function normalizeCatalog(kind: CatalogKind, rows: unknown[]): RemoteCatalogModel[] {
  const inferCaps =
    kind === 'openai'
      ? inferOpenAICapabilities
      : kind === 'gemini'
        ? inferGeminiCapabilities
        : inferAnthropicCapabilities

View on GitHub (pinned to 7205d770c1)