{"record":{"id":"e5ba5a998362a50c","repo":"RocketChat/Rocket.Chat","slug":"error-max-guests-number-reached","errorCode":"error-max-guests-number-reached","errorMessage":"Maximum number of guests reached.","messagePattern":"Maximum number of guests reached\\.","errorType":"exception","errorClass":"MeteorError","httpStatus":null,"severity":"error","filePath":"apps/meteor/ee/server/lib/authorization/validateUserRoles.ts","lineNumber":26,"sourceCode":"\tconst isApp = Boolean(userData.type === 'app');\n\tconst wasApp = Boolean(currentUserData?.type === 'app');\n\n\tconst isBot = Boolean(userData.type === 'bot');\n\tconst wasBot = Boolean(currentUserData?.type === 'bot');\n\n\tconst isGuest = Boolean(userData.roles?.includes('guest') && userData.roles.length === 1);\n\tconst wasGuest = Boolean(currentUserData?.roles?.includes('guest') && currentUserData.roles.length === 1);\n\n\tconst isSpecialType = isApp || isBot;\n\n\tconst hasGuestToChanged = isGuest && !wasGuest;\n\n\tif (isSpecialType) {\n\t\treturn;\n\t}\n\n\tif (hasGuestToChanged && (await License.shouldPreventAction('guestUsers'))) {\n\t\tthrow new MeteorError('error-max-guests-number-reached', 'Maximum number of guests reached.', {\n\t\t\tmethod: 'insertOrUpdateUser',\n\t\t\tfield: 'Assign_role',\n\t\t});\n\t}\n\n\tif (isGuest) {\n\t\treturn;\n\t}\n\n\tconst isActive = Boolean(userData.active !== false);\n\tconst wasActive = currentUserData && currentUserData?.active !== false;\n\n\tconst hasRemovedSpecialType = (wasApp && !isApp) || (wasBot && !isBot);\n\n\tif (!isActive) {\n\t\treturn;\n\t}\n","sourceCodeStart":8,"sourceCodeEnd":44,"githubUrl":"https://github.com/RocketChat/Rocket.Chat/blob/f9d3ec372bb580fa8d036f94cf03925a478ef768/apps/meteor/ee/server/lib/authorization/validateUserRoles.ts#L8-L44","documentation":"Thrown by validateUserRoles when a user is being changed into a guest (roles === ['guest'] where they were not previously a guest) and License.shouldPreventAction('guestUsers') is true — i.e. the enterprise license's guest-user quota is exhausted. MeteorError code 'error-max-guests-number-reached', method 'insertOrUpdateUser', field 'Assign_role'. Apps and bots (isSpecialType) short-circuit before this check.","triggerScenarios":"Admin assigns the 'guest' role to a previously non-guest user (demoting them) when the guest quota is full; bulk user import that converts users to guests beyond the limit; UI 'Assign_role' action that flips a user to guest-only.","commonSituations":"License downgrade reduced the guest allowance; trial license guest seats exhausted; org converted many users to guests for a partner rollout.","solutions":["Free up a guest seat by converting an existing guest to a regular user or deactivating them, then retry.","Upgrade the license to raise the guestUsers cap.","If the conversion is not required, keep the user as a regular user instead of demoting to guest.","Before bulk operations, check current guest count against the license limit."],"exampleFix":"// before: demote beyond limit\nawait Users.updateOne({ _id }, { $set: { roles: ['guest'] } });\nawait validateUserRoles({ roles: ['guest'] }, currentUserData);\n\n// after: verify headroom first\nif (await License.shouldPreventAction('guestUsers')) {\n  throw new Error('Convert an existing guest first or upgrade the license');\n}","handlingStrategy":"validation","validationCode":"async function canDemoteToGuest(): Promise<boolean> {\n  return !(await License.shouldPreventAction('guestUsers'));\n}","typeGuard":"const isGuestOnly = (roles: unknown): roles is ['guest'] =>\n  Array.isArray(roles) && roles.length === 1 && roles[0] === 'guest';","tryCatchPattern":"try { await validateUserRoles({ roles: ['guest'] }, current); } catch (e) {\n  if (e?.error === 'error-max-guests-number-reached') { /* free a seat or upgrade */ } else throw e;\n}","preventionTips":["Check the guest-seat headroom before bulk guest conversions.","Track license caps in admin dashboards so operators see remaining seats."],"tags":["license","users","roles","guest","enterprise"],"backgroundTag":null,"analyzedSha":"f9d3ec372bb580fa8d036f94cf03925a478ef768","analyzedAt":"2026-08-12T19:07:17.372Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}