janhq/jan · error

Failed to fetch model catalog

Error message

Failed to fetch model catalog: ${response.status} ${response.statusText}

What it means

fetchModelCatalog downloads the remote model catalog JSON from MODEL_CATALOG_URL; any non-OK HTTP response throws with the status and status text. The inner message is then rewrapped by the catch block with the same prefix.

Solutions

  1. Check network connectivity and retry
  2. Verify MODEL_CATALOG_URL is correct and the catalog is published
  3. Use a cached/bundled fallback catalog when fetch fails
  4. Check for corporate proxy interference

Example fix

// before
if (!response.ok) {
  throw new Error(`Failed to fetch model catalog: ${response.status} ${response.statusText}`)
}
// after
if (!response.ok) {
  if (response.status === 429) throw new Error('Model catalog rate limited, retry later')
  return fallbackCatalog // use bundled copy
}
Defensive patterns

Strategy: fallback

Validate before calling

const res = await fetch(MODEL_CATALOG_URL)
if (!res.ok) return cachedCatalog

Type guard

null

Try / catch

try { catalog = await fetchModelCatalog() } catch { catalog = bundledFallbackCatalog }

Prevention

When it happens

Trigger: MODEL_CATALOG_URL returns 404/403/500, is rate-limited (429), or an intercepting proxy returns an error page.

Common situations: Catalog URL changed or moved after an app update, CDN outage, offline/behind-firewall environment, or GitHub raw content rate limiting.

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/f532341fc573d365. Report an issue: GitHub.

Appendix: source

Thrown at web-app/src/services/models/default.ts:65

  async getModelContextLimit(modelId: string, provider: string): Promise<number | undefined> {
    const engine = this.getEngine(provider) as (AIEngine & {
      getModelContextLimit?: (id: string) => Promise<number | undefined>
    }) | undefined
    if (!engine?.getModelContextLimit)
      throw new Error('This provider cannot read model context limits. Update its extension or check provider settings.')
    return engine.getModelContextLimit(modelId)
  }

  async fetchModels(): Promise<modelInfo[]> {
    return this.getEngine()?.list() ?? []
  }

  async fetchModelCatalog(): Promise<ModelCatalog> {
    try {
      const response = await fetch(MODEL_CATALOG_URL)

      if (!response.ok) {
        throw new Error(
          `Failed to fetch model catalog: ${response.status} ${response.statusText}`
        )
      }

      const catalog: ModelCatalog = await response.json()
      return catalog
    } catch (error) {
      console.error('Error fetching model catalog:', error)
      throw new Error(
        `Failed to fetch model catalog: ${error instanceof Error ? error.message : 'Unknown error'}`
      )
    }
  }

  async fetchLatestJanModel(): Promise<CatalogModel | null> {
    try {
      const response = await fetch(LATEST_JAN_MODEL_URL)

View on GitHub (pinned to 7205d770c1)