Mintplex-Labs/anything-llm · error
User account suspended.
Error message
User account suspended.
What it means
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.
Source
Thrown at server/models/temporaryAuthToken.js:84
* @param {string} publicToken - the token to validate against
* @returns {Promise<{sessionToken: string|null, token: import("@prisma/client").temporary_auth_tokens & {user: import("@prisma/client").users} | null, error: string | null}>}
*/
validate: async function (publicToken = "") {
/** @type {import("@prisma/client").temporary_auth_tokens & {user: import("@prisma/client").users} | undefined | null} **/
let token;
try {
if (!publicToken)
throw new Error(
"Public token is required to validate a temporary auth token."
);
token = await prisma.temporary_auth_tokens.findUnique({
where: { token: String(publicToken) },
include: { user: true },
});
if (!token) throw new Error("Invalid token.");
if (token.expiresAt < new Date()) throw new Error("Token expired.");
if (token.user.suspended) throw new Error("User account suspended.");
// Create a new session token for the user valid for 30 days
const sessionToken = makeJWT(
{ id: token.user.id, username: token.user.username },
process.env.JWT_EXPIRY
);
return { sessionToken, token, error: null };
} catch (error) {
console.error("FAILED TO VALIDATE TEMPORARY AUTH TOKEN.", error.message);
return { sessionToken: null, token: null, error: error.message };
} finally {
// Delete the token after it has been used under all circumstances if it was retrieved
if (token)
await prisma.temporary_auth_tokens.delete({ where: { id: token.id } });
}
},
};View on GitHub (pinned to 3aec848f28)
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
Example fix
// before
// retrying validation repeatedly after suspension
for (let i = 0; i < 3; i++) await TemporaryAuthToken.validate(publicToken);
// after
const { sessionToken, error } = await TemporaryAuthToken.validate(publicToken);
if (error === 'User account suspended.') {
return res.status(403).send('Account suspended. Contact your administrator.');
} Defensive patterns
Strategy: try-catch
Validate before calling
null // suspension state is authoritative server-side; pre-checking it would race with admin actions
Try / catch
const { sessionToken, error } = await TemporaryAuthToken.validate(publicToken);
if (error === 'User account suspended.') {
// account-state failure: respond 403 and stop - retrying cannot succeed
return res.status(403).json({ error: 'Account suspended. Contact your administrator.' });
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- User is suspended.
- Public token is required to validate a temporary auth token.
- Invalid token.
- Token expired.
- e.message
AI-assisted analysis of Mintplex-Labs/anything-llm@3aec848f28 (2026-08-18).
Data as JSON: /api/errors/f52064a3aed681c6.
Report an issue: GitHub.