{"record":{"id":"23a3a978927e7778","repo":"Mintplex-Labs/anything-llm","slug":"res-statustext-error-fetching-api-key","errorCode":null,"errorMessage":"res.statusText || \"Error fetching api key.\"","messagePattern":"res\\.statusText \\|\\| \"Error fetching api key\\.\"","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"frontend/src/models/system.js","lineNumber":553,"sourceCode":"      headers: baseHeaders(),\n    })\n      .then((res) => {\n        if (res.ok) return { success: true, error: null };\n        throw new Error(\"Error removing logo!\");\n      })\n      .catch((e) => {\n        console.log(e);\n        return { success: false, error: e.message };\n      });\n  },\n  getApiKeys: async function () {\n    return fetch(`${API_BASE}/system/api-keys`, {\n      method: \"GET\",\n      headers: baseHeaders(),\n    })\n      .then((res) => {\n        if (!res.ok) {\n          throw new Error(res.statusText || \"Error fetching api key.\");\n        }\n        return res.json();\n      })\n      .catch((e) => {\n        console.error(e);\n        return { apiKey: null, error: e.message };\n      });\n  },\n  generateApiKey: async function (data = {}) {\n    return fetch(`${API_BASE}/system/generate-api-key`, {\n      method: \"POST\",\n      headers: baseHeaders(),\n      body: JSON.stringify(data),\n    })\n      .then((res) => {\n        if (!res.ok) {\n          throw new Error(res.statusText || \"Error generating api key.\");\n        }","sourceCodeStart":535,"sourceCodeEnd":571,"githubUrl":"https://github.com/Mintplex-Labs/anything-llm/blob/526360e320da9d1b36074be5ed64fe76e5bbfbbd/frontend/src/models/system.js#L535-L571","documentation":"Thrown by System.getApiKeys on a non-2xx GET to /api/system/api-keys. It prefers res.statusText (the HTTP reason phrase) over the generic 'Error fetching api key.', so the surfaced message is often terse (e.g. 'Unauthorized', 'Forbidden'). The .catch() returns {apiKey:null, error:e.message}.","triggerScenarios":"Calling getApiKeys() when the caller is not an admin/manager (403), when the auth token is expired (401), or when the api-keys table/collection is unavailable (500).","commonSituations":"A non-admin user opens the API-keys panel; the token expired mid-session; the API-key feature was disabled in this deployment; backend version predates the /system/api-keys route.","solutions":["Gate the UI behind an admin/manager role check before calling getApiKeys().","Confirm localStorage AUTH_TOKEN is valid (re-check via System.checkAuth).","Read res.statusText — 'Unauthorized'/'Forbidden' pinpoints an authz issue.","Verify the backend version exposes /system/api-keys."],"exampleFix":"// before\nconst { apiKey } = await System.getApiKeys();\n\n// after (role-gate + explicit message)\nif (!isAdmin()) return;\nconst res = await System.getApiKeys();\nif (res.error) showToast(res.error); // surfaces 'Unauthorized' etc.\nelse setApiKey(res.apiKey);","handlingStrategy":"validation","validationCode":"function canFetchApiKeys() {\n  return isAdmin() && !!window.localStorage.getItem(\"anythingllm_authToken\");\n}","typeGuard":"/** @param {any} r @returns {r is {apiKey:string|null, error?:string}} */\nfunction isApiKeysResult(r) {\n  return r != null && (r.apiKey === null || typeof r.apiKey === \"string\");\n}","tryCatchPattern":"if (!canFetchApiKeys()) return;\nconst res = await System.getApiKeys();\nif (!isApiKeysResult(res) || res.error) {\n  showToast(res.error || \"Could not load API keys\");\n}","preventionTips":["Gate the API-keys panel behind an admin/manager role.","Read res.error — statusText pinpoints authz failures.","Re-validate the token via System.checkAuth on 401."],"tags":["network","api-keys","authz","admin"],"backgroundTag":null,"analyzedSha":"526360e320da9d1b36074be5ed64fe76e5bbfbbd","analyzedAt":"2026-08-13T01:45:47.170Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}