janhq/jan · error
No API key configured for
Error message
No API key configured for ${provider.provider}. Add one in Settings > Model Providers. What it means
requireRemoteApiKey throws this when neither the provided key chain nor the provider's stored api_key yields a non-empty key. An empty apiKey still sends an empty auth header upstream, which produces misleading 401s (e.g. Anthropic's 'x-api-key header is required'), so the library fails early with an actionable message pointing at settings.
Solutions
- Add an API key in Settings > Model Providers for this provider.
- Populate the key chain (e.g. from env/config) before invoking the fetch.
- Validate provider.api_key is non-empty at load time and surface a settings prompt instead of failing mid-request.
Example fix
// before
const provider = { provider: 'anthropic', base_url: 'https://api.anthropic.com' }
// after
const provider = { provider: 'anthropic', base_url: 'https://api.anthropic.com', api_key: process.env.ANTHROPIC_API_KEY } Defensive patterns
Strategy: validation
Validate before calling
if (!provider.api_key?.trim() && !(keyChain?.length)) {
openSettingsPrompt(`Add an API key for ${provider.provider}`)
return
} Type guard
const hasApiKey = (p) => typeof p.api_key === 'string' && p.api_key.trim().length > 0
Try / catch
try { await fetchTopRemoteModels(provider, fetch) } catch (e) { if (e.message.startsWith('No API key configured')) { router.push('/settings/providers'); } else throw e } Prevention
- Validate provider records (name, base_url, api_key) at load time.
- Treat empty/whitespace keys as missing, never send them upstream.
- Surface a settings CTA in the UI before any network call.
When it happens
Trigger: Calling a remote provider (fetchTopRemoteModels or chat) with a provider record whose api_key is null/empty and no key in the key chain; user cleared the key field; provider created from a template without credentials.
Common situations: Fresh install with no keys configured; switching a provider to a remote endpoint that requires auth; environment variable supplying an empty string; accidentally trimming away a whitespace-only key.
Understand the failure class
Background: "API key is required" / "API key not found" / "No API key was set": the missing-api-key error family across 16 libraries — this error's family across 16 libraries.
Related errors
- API key rotation exhausted
- Authentication failed: API key is required or invalid for
- Catalog not supported for
- Failed to fetch models from
- Provider configuration is required
AI-assisted analysis of janhq/jan@7205d770c1 (2026-09-17).
Data as JSON: /api/errors/41fca4fdfeafaede.
Report an issue: GitHub.
Appendix: source
Thrown at web-app/src/lib/model-factory.ts:883
res.body?.cancel().catch(() => {})
continue
}
return res
}
throw new Error('API key rotation exhausted')
}
}
// An empty apiKey still puts an empty auth header on the wire, which upstreams
// answer with misleading 401s (e.g. Anthropic's "x-api-key header is
// required"). Fail here with an actionable message instead.
function requireRemoteApiKey(
provider: ProviderObject,
keyChain: string[]
): string {
const key = keyChain[0] ?? provider.api_key?.trim()
if (!key) {
throw new Error(
`No API key configured for ${provider.provider}. Add one in Settings > Model Providers.`
)
}
return key
}
function getRuntimeFetch(): typeof globalThis.fetch {
const maybeWindow = globalThis as typeof globalThis & {
__TAURI__?: unknown
__TAURI_INTERNALS__?: unknown
}
const hasTauriRuntime =
typeof maybeWindow.__TAURI__ !== 'undefined' ||
typeof maybeWindow.__TAURI_INTERNALS__ !== 'undefined'
return isPlatformTauri() && hasTauriRuntime
? (httpFetch as typeof globalThis.fetch)
: globalThis.fetchView on GitHub (pinned to 7205d770c1)