{"record":{"id":"7f020e23c7adfd0b","repo":"RocketChat/Rocket.Chat","slug":"error-invalid-room-7f020e","errorCode":null,"errorMessage":"error-invalid-room","messagePattern":"error-invalid-room","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"apps/meteor/ee/server/local-services/omnichannel.internalService.ts","lineNumber":41,"sourceCode":"\n\tlogger: Logger;\n\n\tconstructor() {\n\t\tsuper();\n\t\tthis.logger = new Logger('OmnichannelEE');\n\t}\n\n\tasync placeRoomOnHold(\n\t\troom: Pick<IOmnichannelRoom, '_id' | 't' | 'open' | 'onHold'>,\n\t\tcomment: string,\n\t\tonHoldBy: Pick<IUser, '_id' | 'username' | 'name'>,\n\t) {\n\t\tthis.logger.debug({ msg: 'Attempting to place room on hold', roomId: room._id, userId: onHoldBy?._id });\n\n\t\tconst { _id: roomId } = room;\n\n\t\tif (!room || !isOmnichannelRoom(room)) {\n\t\t\tthrow new Error('error-invalid-room');\n\t\t}\n\t\tif (!room.open) {\n\t\t\tthrow new Error('error-room-already-closed');\n\t\t}\n\t\tif (room.onHold) {\n\t\t\tthrow new Error('error-room-is-already-on-hold');\n\t\t}\n\t\tconst restrictedOnHold = settings.get('Livechat_allow_manual_on_hold_upon_agent_engagement_only');\n\t\tconst canRoomBePlacedOnHold = !room.onHold;\n\t\tconst canAgentPlaceOnHold = !room.lastMessage?.token;\n\t\tconst canPlaceChatOnHold = canRoomBePlacedOnHold && (!restrictedOnHold || canAgentPlaceOnHold);\n\t\tif (!canPlaceChatOnHold) {\n\t\t\tthrow new Error('error-cannot-place-chat-on-hold');\n\t\t}\n\t\tif (!room.servedBy) {\n\t\t\tthrow new Error('error-unserved-rooms-cannot-be-placed-onhold');\n\t\t}\n","sourceCodeStart":23,"sourceCodeEnd":59,"githubUrl":"https://github.com/RocketChat/Rocket.Chat/blob/b2c16d5842cbe6b69b59bdf6fc5e5f1afcd1f0b0/apps/meteor/ee/server/local-services/omnichannel.internalService.ts#L23-L59","documentation":"OmnichannelInternalService.placeRoomOnHold requires the passed room to be a livechat room: it throws Error('error-invalid-room') when the room is falsy or fails isOmnichannelRoom (i.e. room.t !== 'l'). This is the entry guard that runs before all on-hold state checks (open, onHold, servedBy).","triggerScenarios":"Calling placeRoomOnHold with a non-omnichannel room object - a channel, direct message, or team room (t is 'c'/'d'/'p'/'t') - or with null/undefined, e.g. wiring a generic rooms-list action to the on-hold flow without filtering by type, or not handling a lookup miss.","commonSituations":"Generic room action handlers that show 'place on hold' for every room type; null rooms passed after an unhandled findOneById miss; test fixtures using plain room objects without t: 'l'.","solutions":["Filter actions to omnichannel rooms (t === 'l') before offering or invoking on-hold.","Handle room lookup misses before calling the service so null never reaches it.","Re-fetch the room with its t field included when building the call."],"exampleFix":"// before\nawait service.placeRoomOnHold(anyRoom, comment, user); // anyRoom.t may be 'c'/'d' -> throws\n\n// after\nif (!room || !isOmnichannelRoom(room)) throw new Error('error-invalid-room');\nawait service.placeRoomOnHold(room, comment, user);","handlingStrategy":"type-guard","validationCode":"if (!room || !isOmnichannelRoom(room)) {\n\t// not a livechat room (t !== 'l'); do not offer or invoke placeRoomOnHold\n}","typeGuard":"import { isOmnichannelRoom } from '@rocket.chat/core-typings';\n\nconst isHoldableRoom = (room: unknown): room is Pick<IOmnichannelRoom, '_id' | 't' | 'open' | 'onHold'> =>\n\ttypeof room === 'object' && room !== null && isOmnichannelRoom(room);","tryCatchPattern":"try {\n\tawait service.placeRoomOnHold(room, comment, user);\n} catch (e: any) {\n\tif (e?.message === 'error-invalid-room') return badRequest('Room is not an omnichannel room');\n\tthrow e;\n}","preventionTips":["Show on-hold actions only for rooms with t === 'l'.","Handle room lookup misses before invoking the service so null never reaches it.","Type room payloads as IOmnichannelRoom in omnichannel flows so non-livechat rooms fail at compile time."],"tags":["omnichannel","on-hold","room-type","validation","enterprise"],"backgroundTag":"invalid-room-type","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"}