janhq/jan · error

Failed to fetch models from

Error message

Failed to fetch models from ${provider.provider}: ${lastStatus} ${lastStatusText}

What it means

Thrown after the key-attempt loop is exhausted: every alternative key returned a retryable status (401/403/429) so the function reports the last observed status/statusText. It signals that no configured credential could successfully list models on this provider.

Solutions

  1. Replace the stored keys with a freshly generated, valid API key for the provider.
  2. Check the last status in the message: 429 means rate limited — wait or raise quota; 401/403 means re-authenticate.
  3. Remove stale keys from settings so only one valid key is tried.
  4. Confirm account billing/plan status on the provider dashboard.

Example fix

// before: keys = [expiredKey, alsoExpiredKey]
// after: rotate to a working key in provider settings
provider.api_key = 'sk-<newly-generated-key>'
Defensive patterns

Strategy: try-catch

Validate before calling

// Ensure at least one plausibly-valid key is configured before attempting
if (!provider.api_key?.trim()) throw new Error('No API key configured for ' + provider.provider)

Try / catch

try {
  await fetchModelsFromProvider(provider)
} catch (e) {
  if (e instanceof Error && /Failed to fetch models from .* \d{3}/.test(e.message)) {
    openKeyRotationFlow(provider.provider) // all key attempts exhausted
  }
}

Prevention

When it happens

Trigger: Multiple key attempts configured (e.g. old and new keys) and every attempt failed with 401/403/429; the loop ends and throws with lastStatus/lastStatusText from the final attempt.

Common situations: Both the previous and rotated API keys are expired/revoked; all keys hit the provider's rate limit; keys belong to accounts without access to this endpoint.

Related errors


AI-assisted analysis of janhq/jan@7205d770c1 (2026-09-17). Data as JSON: /api/errors/a6d8c0d4c6e02fd6. Report an issue: GitHub.

Appendix: source

Thrown at web-app/src/services/providers/tauri.ts:247

        if (Array.isArray(data)) {
          return data
            .filter(Boolean)
            .map((model) =>
              typeof model === 'object' && 'id' in model ? model.id : model
            )
        }
        if (data.models && Array.isArray(data.models)) {
          return data.models
            .map((model: string | { id: string }) =>
              typeof model === 'string' ? model : model.id
            )
            .filter(Boolean)
        }
        console.warn('Unexpected response format from provider API:', data)
        return []
      }

      throw new Error(
        `Failed to fetch models from ${provider.provider}: ${lastStatus} ${lastStatusText}`
      )
    } catch (error) {
      console.error('Error fetching models from provider:', error)

      // Preserve structured error messages thrown above
      const structuredErrorPrefixes = [
        'Authentication failed',
        'Access forbidden',
        'Models endpoint not found',
        'Failed to fetch models from',
      ]

      if (
        error instanceof Error &&
        structuredErrorPrefixes.some((prefix) =>
          (error as Error).message.startsWith(prefix)
        )

View on GitHub (pinned to 7205d770c1)