{"record":{"id":"89860c0cc0fc7085","repo":"decolua/9router","slug":"no-active-credentials-for-provider-provider","errorCode":null,"errorMessage":"No active credentials for provider: ${provider}","messagePattern":"No active credentials for provider: (.+?)","errorType":"http","errorClass":null,"httpStatus":404,"severity":"error","filePath":"src/sse/handlers/chat.js","lineNumber":240,"sourceCode":"\n  // Try with available accounts (fallback on errors)\n  const excludeConnectionIds = new Set();\n  let lastError = null;\n  let lastStatus = null;\n\n  while (true) {\n    const credentials = await getProviderCredentials(provider, excludeConnectionIds, model);\n\n    // All accounts unavailable\n    if (!credentials || credentials.allRateLimited) {\n      if (credentials?.allRateLimited) {\n        const errorMsg = lastError || credentials.lastError || \"Unavailable\";\n        const status = lastStatus || Number(credentials.lastErrorCode) || HTTP_STATUS.SERVICE_UNAVAILABLE;\n        log.warn(\"CHAT\", `[${provider}/${model}] ${errorMsg} (${credentials.retryAfterHuman})`);\n        return unavailableResponse(status, `[${provider}/${model}] ${errorMsg}`, credentials.retryAfter, credentials.retryAfterHuman);\n      }\n      if (excludeConnectionIds.size === 0) {\n        log.warn(\"AUTH\", `No active credentials for provider: ${provider}`);\n        return errorResponse(HTTP_STATUS.NOT_FOUND, `No active credentials for provider: ${provider}`);\n      }\n      log.warn(\"CHAT\", \"No more accounts available\", { provider });\n      return errorResponse(lastStatus || HTTP_STATUS.SERVICE_UNAVAILABLE, lastError || \"All accounts unavailable\");\n    }\n\n    // Account selection shown in the unified \"▶\" line (acc:...)\n    const refreshedCredentials = await checkAndRefreshToken(provider, credentials);\n\n    // Ensure real project ID is available for providers that need it (P0 fix: cold miss)\n    if ((provider === \"antigravity\" || provider === \"gemini-cli\") && !refreshedCredentials.projectId) {\n      const pid = await getProjectIdForConnection(credentials.connectionId, refreshedCredentials.accessToken, provider);\n      if (pid) {\n        refreshedCredentials.projectId = pid;\n        // Persist to DB in background so subsequent requests have it immediately\n        updateProviderCredentials(credentials.connectionId, { projectId: pid }).catch(() => { });\n      }\n    }","sourceCodeStart":222,"sourceCodeEnd":258,"githubUrl":"https://github.com/decolua/9router/blob/90b52e06ffd666b7929554211474d01588f6b1f8/src/sse/handlers/chat.js#L222-L258","documentation":"getProviderCredentials found no usable accounts for the provider and excludeConnectionIds is empty, meaning not a single credential (API key/OAuth account) is configured or currently active for that provider. The handler returns 404 'No active credentials for provider: <provider>'.","triggerScenarios":"POST /v1/chat/completions with a model whose provider has zero credentials configured in the gateway, or whose accounts are all disabled/disconnected (e.g. OAuth session never linked).","commonSituations":"Fresh install where the provider was never connected in the dashboard; OAuth account logged out / token revoked and account disabled; credentials deleted during config cleanup; pointing the client at a provider name that exists in the registry but was never set up.","solutions":["Open the 9Router dashboard → Credentials and add or reconnect an account for the named provider.","Re-enable disabled accounts for that provider (they show as disconnected/inactive).","If it's an OAuth provider, complete the OAuth login flow so a token is stored.","Switch the model to a provider you actually have credentials for."],"exampleFix":"// before\n{ \"model\": \"kiro/claude-sonnet-4\" }   // no kiro account linked\n\n// after: link a kiro account in the dashboard first, or use\n{ \"model\": \"openai/gpt-4o\" }          // provider with an active key","handlingStrategy":"fallback","validationCode":"const creds = await fetch(`${base}/dashboard/api/credentials`).then(r => r.json());\nif (!creds.some(c => c.provider === provider && c.active)) {\n  throw new Error(`No active credential for ${provider}; connect one in the dashboard first`);\n}","typeGuard":"null","tryCatchPattern":"const res = await fetch(url, opts);\nif (res.status === 404 && (await res.text()).includes('No active credentials')) {\n  return useFallbackProvider(request); // e.g. switch model to a provider you have set up\n}","preventionTips":["Add credentials for every provider your clients reference before rollout.","Health-check dashboards/credentials as part of deployment.","Re-auth OAuth accounts proactively when tokens near expiry.","Keep combo fallbacks pointing at providers with configured accounts."],"tags":["auth","credentials","provider","configuration"],"backgroundTag":"no-active-credentials","analyzedSha":"90b52e06ffd666b7929554211474d01588f6b1f8","analyzedAt":"2026-08-30T21:05:45.952Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}