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
- Check the status code in the message: 404 means fix base_url to include the correct API path (usually /v1).
- For 401/403/429, replace or wait out the API keys and retry.
- 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
- Verify base_url ends with the correct API root (/v1) for OpenAI-compatible servers.
- Add backoff retry for 5xx statuses before surfacing errors.
- Log statusText plus provider id to speed up triage of upstream outages.
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
- Catalog not supported for
- Failed to fetch model catalog
- MLX API request failed with status
- API request failed with status
- Failed to fetch HuggingFace repository
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)