{"record":{"id":"79c4a0e59d539598","repo":"QuantumNous/new-api","slug":"failed-to-load-api-keys","errorCode":null,"errorMessage":"Failed to load API keys","messagePattern":"Failed to load API keys","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"web/src/features/chat/hooks/use-active-chat-key.ts","lineNumber":28,"sourceCode":"but WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\nGNU Affero General Public License for more details.\n\nYou should have received a copy of the GNU Affero General Public License\nalong with this program. If not, see <https://www.gnu.org/licenses/>.\n\nFor commercial licensing, please contact support@quantumnous.com\n*/\nimport { useQuery } from '@tanstack/react-query'\n\nimport { fetchTokenKey, getApiKeys } from '@/features/keys/api'\nimport { API_KEY_STATUS } from '@/features/keys/constants'\nimport { useAuthStore } from '@/stores/auth-store'\n\nexport async function fetchActiveChatKey() {\n  const result = await getApiKeys({ p: 1, size: 50 })\n  if (!result.success) {\n    throw new Error(result.message || 'Failed to load API keys')\n  }\n\n  const items = result.data?.items ?? []\n  const active = items.find((item) => item.status === API_KEY_STATUS.ENABLED)\n  if (!active) {\n    throw new Error('No enabled API keys found. Create or enable one first.')\n  }\n\n  const keyResult = await fetchTokenKey(active.id)\n  if (!keyResult.success || !keyResult.data?.key) {\n    throw new Error(keyResult.message || 'Failed to load API key')\n  }\n\n  return `sk-${keyResult.data.key}`\n}\n\n/**\n * Get the currently active API key for chat links","sourceCodeStart":10,"sourceCodeEnd":46,"githubUrl":"https://github.com/QuantumNous/new-api/blob/e2c7aa7b102c2075eae2377df3508658d45e88dc/web/src/features/chat/hooks/use-active-chat-key.ts#L10-L46","documentation":"Thrown by fetchActiveChatKey() when getApiKeys({p:1,size:50}) responds with success falsy and no message. The chat-link feature needs an enabled API key, and this is the first step (listing keys) failing — usually an auth or permission problem rather than 'no keys', which has its own error (19).","triggerScenarios":"GET /api/token/ listing failing due to an expired login session; backend error; network envelope with success:false; user with no token-list permission.","commonSituations":"Chat playground opened in a background tab after the session expired; backend restarting when the page loaded; response interceptor converting a 401 into {success:false} without a message.","solutions":["Check the GET /api/token/ request in DevTools — a 401 means the login expired; sign in again.","Reload the page after the backend is healthy.","If the response is a legitimate error envelope, surface its message in the UI.","Consider treating auth-expiry specially so the user is redirected to login instead of seeing this error."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"const auth = useAuthStore.getState()\nif (!auth.isAuthenticated) {\n  redirectToLogin()\n  return\n}","typeGuard":"const isKeyListSuccess = (\n  r: unknown\n): r is { success: true; data: { items: unknown[] } } =>\n  typeof r === 'object' && r !== null && (r as { success?: unknown }).success === true","tryCatchPattern":"try {\n  const key = await fetchActiveChatKey()\n  return key\n} catch (e) {\n  if (/load/i.test(getErrorMessage(e))) {\n    invalidateAuthAndRedirect() // likely expired session\n  }\n  throw e\n}","preventionTips":["Check the login session before lazy-loading the chat feature","Handle 401-shaped envelopes by redirecting to login instead of showing an error toast","Retry the query once after the backend recovers from a restart"],"tags":["api-keys","chat","auth","api-response"],"backgroundTag":null,"analyzedSha":"e2c7aa7b102c2075eae2377df3508658d45e88dc","analyzedAt":"2026-08-15T10:35:18.111Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}