{"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":"error_code","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/b2c16d5842cbe6b69b59bdf6fc5e5f1afcd1f0b0/apps/meteor/ee/server/lib/authorization/validateUserRoles.ts#L8-L44","documentation":"Thrown by validateUserRoles (wired into user create/update and role assignment flows as method 'insertOrUpdateUser') when a user is becoming a guest (roles exactly ['guest'] and previously not) and the license's guest-user allowance is exhausted (License.shouldPreventAction('guestUsers')). App and bot user types bypass the check. It enforces the enterprise guest-seat limit at the moment the guest role is granted.","triggerScenarios":"Creating a user with only the guest role, or editing an existing user's roles down to just 'guest', past the licensed guestUsers limit; SSO/LDAP provisioning assigning the guest role to new external users.","commonSituations":"External-collaboration onboarding exceeding purchased guest seats; guest role bulk-assigned during imports; license tier with few guest seats.","solutions":["Convert other guests back to regular users (or deactivate them) to free guest seats, then retry","Apply a license with a higher guestUsers allowance (Administration > License)","For imports, throttle guest role assignment until the license is upgraded"],"exampleFix":"// before: assigning the guest role and letting the hook throw\nawait insertOrUpdateUser({ ...userData, roles: ['guest'] });\n\n// after: pre-check the same license gate\nimport { License } from '@rocket.chat/license';\nconst becomingGuest = (userData.roles ?? []).includes('guest') && (currentUserData?.roles ?? []).join() !== 'guest';\nif (becomingGuest && (await License.shouldPreventAction('guestUsers'))) {\n  throw new Error('Guest seat limit reached; upgrade the license first');\n}\nawait insertOrUpdateUser({ ...userData, roles: ['guest'] });","handlingStrategy":"validation","validationCode":"import { License } from '@rocket.chat/license';\n\nconst canAddGuest = async (): Promise<boolean> => !(await License.shouldPreventAction('guestUsers'));","typeGuard":"const isGuestOnlyRoles = (roles?: string[]): boolean =>\n  Boolean(roles?.includes('guest') && roles.length === 1);","tryCatchPattern":"try {\n  await insertOrUpdateUser({ ...userData, roles: ['guest'] });\n} catch (err: any) {\n  if (err?.error === 'error-max-guests-number-reached') {\n    // free a guest seat or upgrade the license before retrying the role assignment\n  }\n  throw err;\n}","preventionTips":["Track guest-seat usage against the license before external-collaboration drives","Remember app/bot users bypass the guest check entirely","When converting users, only role changes toward guest-only trigger the gate"],"tags":["license","enterprise","guests","roles","billing-limit"],"backgroundTag":"license-limit-exceeded","analyzedSha":"b2c16d5842cbe6b69b59bdf6fc5e5f1afcd1f0b0","analyzedAt":"2026-08-18T15:26:39.429Z","contentChangedAt":"2026-08-18T15:26:39.429Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}