{"record":{"id":"f52064a3aed681c6","repo":"Mintplex-Labs/anything-llm","slug":"user-account-suspended","errorCode":null,"errorMessage":"User account suspended.","messagePattern":"User account suspended\\.","errorType":"exception","errorClass":null,"httpStatus":401,"severity":"error","filePath":"server/models/temporaryAuthToken.js","lineNumber":84,"sourceCode":"   * @param {string} publicToken - the token to validate against\n   * @returns {Promise<{sessionToken: string|null, token: import(\"@prisma/client\").temporary_auth_tokens & {user: import(\"@prisma/client\").users} | null, error: string | null}>}\n   */\n  validate: async function (publicToken = \"\") {\n    /** @type {import(\"@prisma/client\").temporary_auth_tokens & {user: import(\"@prisma/client\").users} | undefined | null} **/\n    let token;\n\n    try {\n      if (!publicToken)\n        throw new Error(\n          \"Public token is required to validate a temporary auth token.\"\n        );\n      token = await prisma.temporary_auth_tokens.findUnique({\n        where: { token: String(publicToken) },\n        include: { user: true },\n      });\n      if (!token) throw new Error(\"Invalid token.\");\n      if (token.expiresAt < new Date()) throw new Error(\"Token expired.\");\n      if (token.user.suspended) throw new Error(\"User account suspended.\");\n\n      // Create a new session token for the user valid for 30 days\n      const sessionToken = makeJWT(\n        { id: token.user.id, username: token.user.username },\n        process.env.JWT_EXPIRY\n      );\n\n      return { sessionToken, token, error: null };\n    } catch (error) {\n      console.error(\"FAILED TO VALIDATE TEMPORARY AUTH TOKEN.\", error.message);\n      return { sessionToken: null, token: null, error: error.message };\n    } finally {\n      // Delete the token after it has been used under all circumstances if it was retrieved\n      if (token)\n        await prisma.temporary_auth_tokens.delete({ where: { id: token.id } });\n    }\n  },\n};","sourceCodeStart":66,"sourceCodeEnd":102,"githubUrl":"https://github.com/Mintplex-Labs/anything-llm/blob/3aec848f2885144aa8f1e53b9731a04310d5d558/server/models/temporaryAuthToken.js#L66-L102","documentation":"validate() found a valid, unexpired token, but the linked user record has suspended=true, so authentication is refused and no session JWT is minted. This is an account-state rejection, not a token problem.","triggerScenarios":"An admin suspended the user after the token was created; a previously suspended user retries an old magic link; bulk moderation actions suspending accounts while login links were outstanding.","commonSituations":"Abuse-response workflows suspending accounts mid-login; offboarded employees clicking cached login links; shared inboxes where a suspended account's link is reused by someone else.","solutions":["An administrator must unsuspend the user (users.suspended = false) before this login path can work","If suspension is intentional, present an 'account suspended' message and stop - do not retry","Use a different, active account if the suspended one is not yours"],"exampleFix":"// before\n// retrying validation repeatedly after suspension\nfor (let i = 0; i < 3; i++) await TemporaryAuthToken.validate(publicToken);\n\n// after\nconst { sessionToken, error } = await TemporaryAuthToken.validate(publicToken);\nif (error === 'User account suspended.') {\n  return res.status(403).send('Account suspended. Contact your administrator.');\n}","handlingStrategy":"try-catch","validationCode":"null // suspension state is authoritative server-side; pre-checking it would race with admin actions","typeGuard":null,"tryCatchPattern":"const { sessionToken, error } = await TemporaryAuthToken.validate(publicToken);\nif (error === 'User account suspended.') {\n  // account-state failure: respond 403 and stop - retrying cannot succeed\n  return res.status(403).json({ error: 'Account suspended. Contact your administrator.' });\n}","preventionTips":["Map this error to 403, not 401 - the credential is fine, the account is not","Do not auto-retry: only an admin unsuspending the user can change the outcome","Audit suspended users before sending magic links to their addresses"],"tags":["auth","account-state","suspension"],"backgroundTag":"account-suspended","analyzedSha":"3aec848f2885144aa8f1e53b9731a04310d5d558","analyzedAt":"2026-08-18T10:02:21.017Z","schemaVersion":2},"datasetVersion":"2026-08-23T16:17:53.355Z"}