{"record":{"id":"3481c3c3a86c82c5","repo":"RocketChat/Rocket.Chat","slug":"error-not-allowed-3481c3","errorCode":null,"errorMessage":"error-not-allowed","messagePattern":"error-not-allowed","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"apps/meteor/server/api/v1/omnichannel/departments.ts","lineNumber":156,"sourceCode":"\t\t\t// to show the \"new\" view. Returning 404 breaks it\n\n\t\t\treturn API.v1.success({ department, agents });\n\t\t},\n\t\tasync put() {\n\t\t\tconst permissionToSave = await hasPermissionAsync(this.user, 'manage-livechat-departments');\n\t\t\tconst permissionToAddAgents = await hasPermissionAsync(this.user, 'add-livechat-department-agents');\n\n\t\t\tcheck(this.bodyParams, {\n\t\t\t\tdepartment: Object,\n\t\t\t\tagents: Match.Maybe(Array),\n\t\t\t\tdepartmentUnit: Match.Maybe({ _id: Match.Optional(String) }),\n\t\t\t});\n\n\t\t\tconst { _id } = this.urlParams;\n\t\t\tconst { department, agents, departmentUnit } = this.bodyParams;\n\n\t\t\tif (!permissionToSave) {\n\t\t\t\tthrow new Error('error-not-allowed');\n\t\t\t}\n\n\t\t\tconst agentParam = permissionToAddAgents && agents ? { upsert: agents } : {};\n\t\t\tawait saveDepartment(this.userId, _id, department, agentParam, departmentUnit || {});\n\n\t\t\treturn API.v1.success({\n\t\t\t\tdepartment: await LivechatDepartment.findOneById(_id),\n\t\t\t\tagents: await LivechatDepartmentAgents.findByDepartmentId(_id).toArray(),\n\t\t\t});\n\t\t},\n\t\tasync delete() {\n\t\t\tcheck(this.urlParams, {\n\t\t\t\t_id: String,\n\t\t\t});\n\n\t\t\tconst isRemoveEnabled = settings.get<boolean>('Omnichannel_enable_department_removal');\n\n\t\t\tif (!isRemoveEnabled) {","sourceCodeStart":138,"sourceCodeEnd":174,"githubUrl":"https://github.com/RocketChat/Rocket.Chat/blob/f9d3ec372bb580fa8d036f94cf03925a478ef768/apps/meteor/server/api/v1/omnichannel/departments.ts#L138-L174","documentation":"Thrown by PUT /livechat/department/:_id when the authenticated user lacks the `manage-livechat-departments` permission. IMPORTANT nuance: the route-level guard (departments.ts:117) allows PUT with hasAny(`manage-livechat-departments`, `add-livechat-department-agents`), but the action body re-checks (departments.ts:143-156) and requires `manage-livechat-departments` specifically. So a user holding only `add-livechat-department-agents` passes the route guard yet fails inside the handler. Returns HTTP 400 { success:false, error:'error-not-allowed' }.","triggerScenarios":"PUT /livechat/department/:_id by a user/role that has `add-livechat-department-agents` but NOT `manage-livechat-departments`. The route guard admits the request, the action then rejects it.","commonSituations":"An agent-manager role intended only to add agents to a department tries to edit department settings; permission was recently revoked; role misconfiguration; the route/action permission divergence is unintended.","solutions":["Grant the calling user/role the `manage-livechat-departments` permission.","If the caller only needs to manage agents on a department, use POST /livechat/department/:_id/agents instead of PUT on the department itself.","Reconcile the route-level vs action-level permission mismatch (the action over-constrains relative to the declared route guard) if the divergence is a bug."],"exampleFix":"// before: role has only 'add-livechat-department-agents' -> PUT /livechat/department/:_id throws error-not-allowed\n\n// after: assign the required permission to the role\nawait Roles.addPermissionRoles('manage-livechat-departments', ['livechat-manager']);","handlingStrategy":"validation","validationCode":"const canManage = await hasPermissionAsync(user, 'manage-livechat-departments');\nif (!canManage) {\n  // route to POST /livechat/department/:_id/agents instead, or surface forbidden\n  throw new Error('caller lacks manage-livechat-departments');\n}","typeGuard":"const canManageDepartment = async (user: IUser) =>\n  await hasPermissionAsync(user, 'manage-livechat-departments');","tryCatchPattern":"try {\n  await putDepartment(_id, department, agents, departmentUnit);\n} catch (e) {\n  if (e instanceof Error && e.message === 'error-not-allowed') {\n    // caller needs manage-livechat-departments; fall back to the agents endpoint\n  } else { throw e; }\n}","preventionTips":["UI should only show the department-edit form to users with `manage-livechat-departments`.","For agent-only roles, route to /livechat/department/:_id/agents.","Track the route/action permission divergence (departments.ts:117 vs :143) as a known issue."],"tags":["livechat","omnichannel","permission","departments","rest-api"],"backgroundTag":null,"analyzedSha":"f9d3ec372bb580fa8d036f94cf03925a478ef768","analyzedAt":"2026-08-12T19:07:17.372Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}