{"record":{"id":"41fca4fdfeafaede","repo":"janhq/jan","slug":"no-api-key-configured-for-provider-provider-ad","errorCode":null,"errorMessage":"No API key configured for ${provider.provider}. Add one in Settings > Model Providers.","messagePattern":"No API key configured for (.+?)\\. Add one in Settings > Model Providers\\.","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"web-app/src/lib/model-factory.ts","lineNumber":883,"sourceCode":"        res.body?.cancel().catch(() => {})\n        continue\n      }\n      return res\n    }\n    throw new Error('API key rotation exhausted')\n  }\n}\n\n// An empty apiKey still puts an empty auth header on the wire, which upstreams\n// answer with misleading 401s (e.g. Anthropic's \"x-api-key header is\n// required\"). Fail here with an actionable message instead.\nfunction requireRemoteApiKey(\n  provider: ProviderObject,\n  keyChain: string[]\n): string {\n  const key = keyChain[0] ?? provider.api_key?.trim()\n  if (!key) {\n    throw new Error(\n      `No API key configured for ${provider.provider}. Add one in Settings > Model Providers.`\n    )\n  }\n  return key\n}\n\nfunction getRuntimeFetch(): typeof globalThis.fetch {\n  const maybeWindow = globalThis as typeof globalThis & {\n    __TAURI__?: unknown\n    __TAURI_INTERNALS__?: unknown\n  }\n  const hasTauriRuntime =\n    typeof maybeWindow.__TAURI__ !== 'undefined' ||\n    typeof maybeWindow.__TAURI_INTERNALS__ !== 'undefined'\n\n  return isPlatformTauri() && hasTauriRuntime\n    ? (httpFetch as typeof globalThis.fetch)\n    : globalThis.fetch","sourceCodeStart":865,"sourceCodeEnd":901,"githubUrl":"https://github.com/janhq/jan/blob/7205d770c1e097c3daf35a911176410e93bc5564/web-app/src/lib/model-factory.ts#L865-L901","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nconst provider = { provider: 'anthropic', base_url: 'https://api.anthropic.com' }\n// after\nconst provider = { provider: 'anthropic', base_url: 'https://api.anthropic.com', api_key: process.env.ANTHROPIC_API_KEY }","handlingStrategy":"validation","validationCode":"if (!provider.api_key?.trim() && !(keyChain?.length)) {\n  openSettingsPrompt(`Add an API key for ${provider.provider}`)\n  return\n}","typeGuard":"const hasApiKey = (p) => typeof p.api_key === 'string' && p.api_key.trim().length > 0","tryCatchPattern":"try { await fetchTopRemoteModels(provider, fetch) } catch (e) { if (e.message.startsWith('No API key configured')) { router.push('/settings/providers'); } else throw e }","preventionTips":["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."],"tags":["api-key","authentication","configuration","provider"],"backgroundTag":"missing-api-key","analyzedSha":"7205d770c1e097c3daf35a911176410e93bc5564","analyzedAt":"2026-09-17T14:27:30.100Z","contentChangedAt":"2026-09-17T14:27:30.100Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}