{"record":{"id":"868e9ce62e84c638","repo":"Mintplex-Labs/anything-llm","slug":"user-is-suspended","errorCode":null,"errorMessage":"User is suspended.","messagePattern":"User is suspended\\.","errorType":"http","errorClass":null,"httpStatus":400,"severity":"error","filePath":"server/endpoints/mobile/middleware/index.js","lineNumber":31,"sourceCode":"  try {\n    const token = request.header(\"x-anythingllm-mobile-device-token\");\n    if (!token)\n      return response.status(400).json({ error: \"Device token is required\" });\n\n    const device = await MobileDevice.get(\n      { token: String(token) },\n      { user: true }\n    );\n    if (!device)\n      return response.status(400).json({ error: \"Device not found\" });\n    if (!device.approved)\n      return response.status(400).json({ error: \"Device not approved\" });\n\n    // If the device is associated with a user then we can associate it with the locals\n    // so we can reuse it later.\n    if (device.user) {\n      if (device.user.suspended)\n        return response.status(400).json({ error: \"User is suspended.\" });\n      response.locals.user = device.user;\n    }\n\n    delete device.user;\n    response.locals.device = device;\n    next();\n  } catch (error) {\n    console.error(\"validDeviceToken\", error);\n    response.status(500).json({ error: \"Invalid middleware response\" });\n  }\n}\n\n/**\n * Validates a temporary registration token that is passed in the request\n * and associates the user with the token (if valid). Temporary token is consumed\n * and cannot be used again after this middleware is called.\n * @param {*} request\n * @param {*} response","sourceCodeStart":13,"sourceCodeEnd":49,"githubUrl":"https://github.com/Mintplex-Labs/anything-llm/blob/3aec848f2885144aa8f1e53b9731a04310d5d558/server/endpoints/mobile/middleware/index.js#L13-L49","documentation":"After token and approval checks pass, validDeviceToken loads the device's owning user (MobileDevice.get with { user: true }); if that user has suspended = true it responds 400 { error: 'User is suspended.' } and never attaches the user to response.locals. A suspended owner blocks the device even when the device itself is approved.","triggerScenarios":"Admin suspends the user account that owns the device while the paired app keeps making requests; a device registered under an account that is later suspended.","commonSituations":"Employee offboarding: account suspended but the phone app still installed and polling; suspension during an active pairing.","solutions":["Admin must unsuspend the account (multi-user settings) to restore device access","Or pair the device to a different active account via fresh connect-info","On the client, surface 'account suspended — contact admin' and stop retrying"],"exampleFix":null,"handlingStrategy":"fallback","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  await api.command('workspaces');\n} catch (e) {\n  if (e.status === 400 && e.body?.error === 'User is suspended.') {\n    return showFatal('Account suspended — contact your administrator');\n  }\n  throw e;\n}","preventionTips":["Treat suspension as a terminal state in the app — no auto-retry","Show a clear 'contact admin' message instead of a generic error","Admins: prefer unapproving/deleting the device rather than suspending owners when only device access should end"],"tags":["mobile","auth","suspended","multi-user","account-state"],"backgroundTag":"user-account-suspended","analyzedSha":"3aec848f2885144aa8f1e53b9731a04310d5d558","analyzedAt":"2026-08-18T10:02:21.017Z","schemaVersion":2},"datasetVersion":"2026-08-23T16:17:53.355Z"}