{"record":{"id":"434f9bb495cb58dd","repo":"RocketChat/Rocket.Chat","slug":"error-max-departments-number-reached","errorCode":"error-max-departments-number-reached","errorMessage":"Maximum number of departments reached","messagePattern":"Maximum number of departments reached","errorType":"error_code","errorClass":"Meteor.Error","httpStatus":null,"severity":"error","filePath":"apps/meteor/server/lib/omnichannel/departmentsLib.ts","lineNumber":52,"sourceCode":"\t}\n\n\tconst department = _id\n\t\t? await LivechatDepartment.findOneById<Pick<ILivechatDepartment, '_id' | 'archived' | 'enabled' | 'parentId'>>(_id, {\n\t\t\t\tprojection: { _id: 1, archived: 1, enabled: 1, parentId: 1 },\n\t\t\t})\n\t\t: null;\n\n\tif (departmentUnit && !departmentUnit._id && department && department.parentId) {\n\t\tconst isLastDepartmentInUnit = (await LivechatDepartment.countDepartmentsInUnit(department.parentId)) === 1;\n\t\tif (isLastDepartmentInUnit) {\n\t\t\tthrow new Meteor.Error('error-unit-cant-be-empty', \"The last department in a unit can't be removed\", {\n\t\t\t\tmethod: 'livechat:saveDepartment',\n\t\t\t});\n\t\t}\n\t}\n\n\tif (!department && !(await isDepartmentCreationAvailable())) {\n\t\tthrow new Meteor.Error('error-max-departments-number-reached', 'Maximum number of departments reached', {\n\t\t\tmethod: 'livechat:saveDepartment',\n\t\t});\n\t}\n\n\tif (department?.archived && departmentData.enabled) {\n\t\tthrow new Meteor.Error('error-archived-department-cant-be-enabled', 'Archived departments cant be enabled', {\n\t\t\tmethod: 'livechat:saveDepartment',\n\t\t});\n\t}\n\n\t// TODO: Use AJV or Zod for validation (or the lib we are using rn)\n\tconst defaultValidations: Record<string, Match.Matcher<any> | BooleanConstructor | StringConstructor> = {\n\t\tenabled: Boolean,\n\t\tname: String,\n\t\tdescription: Match.Optional(String),\n\t\tshowOnRegistration: Boolean,\n\t\temail: String,\n\t\tshowOnOfflineForm: Boolean,","sourceCodeStart":34,"sourceCodeEnd":70,"githubUrl":"https://github.com/RocketChat/Rocket.Chat/blob/b2c16d5842cbe6b69b59bdf6fc5e5f1afcd1f0b0/apps/meteor/server/lib/omnichannel/departmentsLib.ts#L34-L70","documentation":"Thrown by the `livechat:saveDepartment` Meteor method when creating a NEW department (no existing department id) while `isDepartmentCreationAvailable()` returns false. In the community edition that helper only returns true when `LivechatDepartment.countTotal() === 0` (packages/omni-core/src/isDepartmentCreationAvailable.ts), i.e. only ONE department is ever allowed; unlimited departments require the `livechat-enterprise` license module (ee/packages/omni-core-ee/src/isDepartmentCreationAvailable.ts).","triggerScenarios":"Calling `livechat:saveDepartment` (or the REST `POST /v1/livechat/department`) with no `_id` while at least one LivechatDepartment document already exists on a server without the livechat-enterprise license module.","commonSituations":"Community/self-hosted installs where an admin already created a default department and then tries to add a second one; trials where the Enterprise license expired, silently re-enabling the single-department limit; imports/seeds that attempt to insert multiple departments.","solutions":["Verify the limit first via `GET /v1/livechat/department/isDepartmentCreationAvailable` (mirrors apps/meteor/client/views/omnichannel/departments/NewDepartment.tsx) and hide/disable the 'New Department' UI when it returns false","If more departments are needed, install/enable an Enterprise license with the `livechat-enterprise` module, which patches the check to always allow creation","Reuse or edit the existing department (`livechat:saveDepartment` with its `_id`) instead of creating a new one","Delete the existing department to drop countTotal() back to 0 (only viable when one department is genuinely enough)"],"exampleFix":"// before\nawait Meteor.callAsync('livechat:saveDepartment', null, deptData);\n\n// after\nconst { isDepartmentCreationAvailable } = await useEndpoint('GET', '/v1/livechat/department/isDepartmentCreationAvailable')();\nif (!isDepartmentCreationAvailable) {\n  throw new Error('Maximum number of departments reached for this license');\n}\nawait Meteor.callAsync('livechat:saveDepartment', null, deptData);","handlingStrategy":"validation","validationCode":"// Server-side or via REST before creating\nconst available = await isDepartmentCreationAvailable(); // or GET /v1/livechat/department/isDepartmentCreationAvailable\nif (!available) {\n  throw new Error('Department quota reached — upgrade license or edit the existing department');\n}\nawait saveDepartment(null, deptData);","typeGuard":"const canCreateDepartments = async (): Promise<boolean> =>\n  (await fetch('/api/v1/livechat/department/isDepartmentCreationAvailable')\n    .then((r) => r.json())).isDepartmentCreationAvailable === true;","tryCatchPattern":"try {\n  await saveDepartment(null, deptData);\n} catch (e) {\n  if (isMeteorError(e, 'error-max-departments-number-reached')) {\n    // surface license/quota messaging, not a generic failure\n  }\n}","preventionTips":["Query isDepartmentCreationAvailable before rendering the 'New Department' action (as NewDepartment.tsx does)","Track license module availability (livechat-enterprise) in admin tooling","Prefer editing the single existing department over creating new ones on community edition"],"tags":["omnichannel","departments","license","livechat","quota"],"backgroundTag":"license-limit-reached","analyzedSha":"b2c16d5842cbe6b69b59bdf6fc5e5f1afcd1f0b0","analyzedAt":"2026-08-18T15:26:39.429Z","contentChangedAt":"2026-08-18T15:26:39.429Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}