{"record":{"id":"84aa97c23c106708","repo":"Mintplex-Labs/anything-llm","slug":"failed-to-disconnect-and-revoke-api-key","errorCode":null,"errorMessage":"Failed to disconnect and revoke API key","messagePattern":"Failed to disconnect and revoke API key","errorType":"http","errorClass":null,"httpStatus":500,"severity":"error","filePath":"server/endpoints/browserExtension.js","lineNumber":57,"sourceCode":"          .json({ connected: false, error: \"Failed to fetch workspaces\" });\n      }\n    }\n  );\n\n  app.delete(\n    \"/browser-extension/disconnect\",\n    [validBrowserExtensionApiKey],\n    async (_request, response) => {\n      try {\n        const apiKeyId = response.locals.apiKey.id;\n        const { success, error } =\n          await BrowserExtensionApiKey.delete(apiKeyId);\n        if (!success) throw new Error(error);\n        response.status(200).json({ success: true });\n      } catch (error) {\n        console.error(error);\n        response\n          .status(500)\n          .json({ error: \"Failed to disconnect and revoke API key\" });\n      }\n    }\n  );\n\n  app.get(\n    \"/browser-extension/workspaces\",\n    [validBrowserExtensionApiKey],\n    async (request, response) => {\n      try {\n        const user = await userFromSession(request, response);\n        const workspaces = multiUserMode(response)\n          ? await Workspace.whereWithUser(user)\n          : await Workspace.where();\n\n        response.status(200).json({ workspaces });\n      } catch (error) {\n        console.error(error);","sourceCodeStart":39,"sourceCodeEnd":75,"githubUrl":"https://github.com/Mintplex-Labs/anything-llm/blob/3aec848f2885144aa8f1e53b9731a04310d5d558/server/endpoints/browserExtension.js#L39-L75","documentation":"HTTP 500 from DELETE /api/browser-extension/disconnect, which revokes the browser extension's API key via BrowserExtensionApiKey.delete(apiKeyId). The handler throws (and converts to this message) when delete reports {success:false, error}, or when the DB delete itself throws - e.g. the key row was already removed, the database is unavailable, or response.locals.apiKey was not populated. The original error is only in the server console.","triggerScenarios":"Disconnect clicked twice (second call may already lack a valid key row); database down or locked when deleting the key; middleware and handler disagreeing on the current key after rotation.","commonSituations":"Retry storms from the extension UI racing multiple disconnects; server storage issues; a key revoked out-of-band (expired/cleanup job) before the user pressed disconnect.","solutions":["Check server logs for the console.error output naming the real cause","Retry disconnect once after refreshing the extension - an already-revoked key usually resolves itself","If it persists, verify DB health (volume, disk, locks)","Re-connect the extension to mint a new key, which replaces dangling state"],"exampleFix":"// before\nawait disconnect(); // fire-and-forget, throws on 500\n// after\nconst res = await disconnect();\nif (!res.ok && res.status !== 500) await reconnect();\n// 500 with revoked/missing key is effectively disconnected - drop local key either way\nclearStoredKey();","handlingStrategy":"fallback","validationCode":null,"typeGuard":"function isDisconnectFailure(d) { return typeof d?.error === 'string' && /disconnect/i.test(d.error); }","tryCatchPattern":"try { await disconnect(); }\ncatch (e) {\n  clearLocalApiKey(); // 500 here often means the key is already gone - clearing local state is the safe end state\n  if (persistsOnNextConnect()) await reconnect();\n}","preventionTips":["Make disconnect idempotent in the extension client - clearing local state on any outcome","Debounce the disconnect button to avoid racing duplicate calls","If 500 persists, re-connect to mint a fresh key and retry disconnect","Check server logs for the underlying BrowserExtensionApiKey.delete error"],"tags":["anythingllm","browser-extension","api-key","http-500","revocation"],"backgroundTag":"api-key-revocation-failed","analyzedSha":"3aec848f2885144aa8f1e53b9731a04310d5d558","analyzedAt":"2026-08-18T10:02:21.017Z","schemaVersion":2},"datasetVersion":"2026-08-21T13:17:26.733Z"}