{"record":{"id":"dc3ed8e8ebf73172","repo":"RocketChat/Rocket.Chat","slug":"not-authorized-dc3ed8","errorCode":"Not_authorized","errorMessage":"Not_authorized","messagePattern":"Not_authorized","errorType":"exception","errorClass":"Error","httpStatus":400,"severity":"error","filePath":"apps/meteor/ee/server/api/v1/omnichannel/rooms.ts","lineNumber":34,"sourceCode":"\t\tvalidateParams: isLivechatRoomOnHoldProps,\n\t\tlicense: ['livechat-enterprise'],\n\t},\n\t{\n\t\tasync post() {\n\t\t\tconst { roomId } = this.bodyParams;\n\n\t\t\ttype Room = Pick<IOmnichannelRoom, '_id' | 't' | 'open' | 'onHold' | 'u' | 'lastMessage' | 'servedBy'>;\n\n\t\t\tconst room = await LivechatRooms.findOneById<Room>(roomId, {\n\t\t\t\tprojection: { _id: 1, t: 1, open: 1, onHold: 1, u: 1, lastMessage: 1, servedBy: 1 },\n\t\t\t});\n\t\t\tif (!room) {\n\t\t\t\tthrow new Error('error-invalid-room');\n\t\t\t}\n\n\t\t\tconst subscription = await Subscriptions.findOneByRoomIdAndUserId(roomId, this.userId, { projection: { _id: 1 } });\n\t\t\tif (!subscription && !(await hasPermissionAsync(this.user, 'on-hold-others-livechat-room'))) {\n\t\t\t\tthrow new Error('Not_authorized');\n\t\t\t}\n\n\t\t\tconst onHoldBy = { _id: this.userId, username: this.user.username, name: this.user.name };\n\t\t\tconst comment = i18n.t('Omnichannel_On_Hold_manually', {\n\t\t\t\tuser: onHoldBy.name || `@${onHoldBy.username}`,\n\t\t\t});\n\n\t\t\tawait OmnichannelEEService.placeRoomOnHold(room, comment, this.user);\n\n\t\t\treturn API.v1.success();\n\t\t},\n\t},\n);\n\nAPI.v1.addRoute(\n\t'livechat/room.resumeOnHold',\n\t{\n\t\tauthRequired: true,","sourceCodeStart":16,"sourceCodeEnd":52,"githubUrl":"https://github.com/RocketChat/Rocket.Chat/blob/b2c16d5842cbe6b69b59bdf6fc5e5f1afcd1f0b0/apps/meteor/ee/server/api/v1/omnichannel/rooms.ts#L16-L52","documentation":"After the room is found, room.onHold requires the caller to either have a subscription in that room or hold the on-hold-others-livechat-room permission; otherwise Not_authorized. Entering the route already required on-hold-livechat-room, so this throw specifically means: room exists, but this user is neither in it nor allowed to act on others' rooms.","triggerScenarios":"A livechat manager calling POST /api/v1/livechat/room.onHold for an agent's conversation they are not a member of, while their role lacks on-hold-others-livechat-room.","commonSituations":"New manager roles missing the 'on-hold-others-livechat-room' permission; supervisors using service accounts with no room subscriptions; permission sets cloned from agent roles that only include on-hold-livechat-room.","solutions":["Grant on-hold-others-livechat-room to the caller's role (Administration -> Permissions).","Or perform the call as the serving agent, i.e. a user subscribed to the room.","Verify the caller's effective role/permission mapping before retrying."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  await api.post('/v1/livechat/room.onHold', { roomId });\n} catch (e) {\n  if (e?.response?.data?.errorType === 'Not_authorized') {\n    // caller is not in the room: either act as the serving agent\n    // or have an admin grant 'on-hold-others-livechat-room' to the role\n  } else throw e;\n}","preventionTips":["Audit role permissions before building on-hold automations: route permission is not enough.","Prefer executing on-hold as a user subscribed to the room.","Distinguish 403 Not_authorized from invalid-room in error reporting."],"tags":["omnichannel","livechat","on-hold","permissions","authorization"],"backgroundTag":"permission-denied","analyzedSha":"b2c16d5842cbe6b69b59bdf6fc5e5f1afcd1f0b0","analyzedAt":"2026-08-18T15:26:39.429Z","schemaVersion":2},"datasetVersion":"2026-08-21T13:17:26.733Z"}