{"record":{"id":"bf9c5997d81c3f4b","repo":"RocketChat/Rocket.Chat","slug":"error-not-allowed-bf9c59","errorCode":"error-not-allowed","errorMessage":"error-not-allowed","messagePattern":"error-not-allowed","errorType":"exception","errorClass":"Error","httpStatus":400,"severity":"error","filePath":"apps/meteor/server/api/v1/omnichannel/room.ts","lineNumber":430,"sourceCode":"\t\t\t\tthrow new Error('error-invalid-user');\n\t\t\t}\n\n\t\t\tconst room = await LivechatRooms.findOneById(roomId);\n\n\t\t\tif (!room) {\n\t\t\t\tthrow new Error('error-invalid-room');\n\t\t\t}\n\n\t\t\tif (!room.open) {\n\t\t\t\tthrow new Error('room-closed');\n\t\t\t}\n\n\t\t\tif (!(await Omnichannel.isWithinMACLimit(room))) {\n\t\t\t\tthrow new Error('error-mac-limit-reached');\n\t\t\t}\n\n\t\t\tif (!(await canAccessRoomAsync(room, user))) {\n\t\t\t\tthrow new Error('error-not-allowed');\n\t\t\t}\n\n\t\t\tawait addUserToRoom(roomId, user);\n\n\t\t\treturn API.v1.success();\n\t\t},\n\t},\n);\n\nAPI.v1.addRoute(\n\t'livechat/room.saveInfo',\n\t{ authRequired: true, permissionsRequired: ['view-l-room'], validateParams: isLiveChatRoomSaveInfoProps },\n\t{\n\t\tasync post() {\n\t\t\tconst { roomData, guestData } = this.bodyParams;\n\t\t\tconst room = await LivechatRooms.findOneById(roomData._id);\n\t\t\tif (!room || !isOmnichannelRoom(room)) {\n\t\t\t\tthrow new Error('error-invalid-room');","sourceCodeStart":412,"sourceCodeEnd":448,"githubUrl":"https://github.com/RocketChat/Rocket.Chat/blob/f9d3ec372bb580fa8d036f94cf03925a478ef768/apps/meteor/server/api/v1/omnichannel/room.ts#L412-L448","documentation":"Thrown by GET livechat/room.join when canAccessRoomAsync(room, user) returns false. Even with view-l-room permission, the user must pass the room-level access check; for Livechat rooms this typically requires being the assigned agent, a manager/admin, or a member of the department. The guard enforces per-room authorization after the global permission gate.","triggerScenarios":"GET livechat/room.join?roomId=... by an agent who is not the serving agent, not in the room's department, and lacks manager-level omnichannel permissions. Also when a non-omnichannel user with view-l-room tries to join a department-restricted room.","commonSituations":"Agent from department A tries to join a department B room without cross-department permission; ex-serving agent whose assignment was revoked tries to rejoin; user has view-l-room but not view-livechat-manager or livechat-monitoring.","solutions":["Grant the user membership in the room's department or assign them as a co-agent.","Give the user view-livechat-manager (or equivalent) for cross-department monitoring.","Confirm the user still holds view-l-room; permission revocation is a common cause.","Use the proper supervisor/monitor role instead of forcing a direct join."],"exampleFix":"// before\nawait GET('/api/v1/livechat/room.join', { roomId });\n\n// after\nif (!await canAccessRoomAsync(room, user)) {\n  await requestDepartmentMembership(room.departmentId, user._id);\n  return;\n}\nawait GET('/api/v1/livechat/room.join', { roomId });","handlingStrategy":"validation","validationCode":"const allowed = await canAccessRoomAsync(room, user);\nif (!allowed) throw new ClientError('not-allowed');","typeGuard":"null","tryCatchPattern":"try {\n  await GET('/api/v1/livechat/room.join', { roomId });\n} catch (e) {\n  if (e.message === 'error-not-allowed') { requestDepartmentAccess(room.departmentId); return; }\n  throw e;\n}","preventionTips":["Pre-check canAccessRoomAsync in the UI to disable join buttons the user cannot use.","Keep department membership and view-livechat-manager permissions aligned with the org chart.","Use the supervisor/monitor role for read-only cross-department access instead of forcing joins."],"tags":["omnichannel","livechat","authorization","room-join","permissions"],"backgroundTag":null,"analyzedSha":"f9d3ec372bb580fa8d036f94cf03925a478ef768","analyzedAt":"2026-08-12T19:07:17.372Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}