{"record":{"id":"ff0c04bcf762e82a","repo":"RocketChat/Rocket.Chat","slug":"this-conversation-is-already-closed","errorCode":null,"errorMessage":"This_conversation_is_already_closed","messagePattern":"This_conversation_is_already_closed","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"apps/meteor/ee/server/local-services/omnichannel.internalService.ts","lineNumber":90,"sourceCode":"\t\t}\n\n\t\tawait callbacks.run('livechat:afterOnHold', room);\n\t}\n\n\tasync resumeRoomOnHold(\n\t\troom: Pick<IOmnichannelRoom, '_id' | 't' | 'open' | 'onHold' | 'servedBy'>,\n\t\tcomment: string,\n\t\tresumeBy: Pick<IUser, '_id' | 'username' | 'name'>,\n\t\tclientAction = false,\n\t) {\n\t\tthis.logger.debug({ msg: 'Attempting to resume room on hold', roomId: room._id, userId: resumeBy?._id });\n\n\t\tif (!room || !isOmnichannelRoom(room)) {\n\t\t\tthrow new Error('error-invalid-room');\n\t\t}\n\n\t\tif (!room.open) {\n\t\t\tthrow new Error('This_conversation_is_already_closed');\n\t\t}\n\n\t\tif (!room.onHold) {\n\t\t\tthrow new Error('error-room-not-on-hold');\n\t\t}\n\n\t\tconst { _id: roomId, servedBy } = room;\n\n\t\tif (!servedBy) {\n\t\t\tthis.logger.error({ msg: 'No serving agent found for room', roomId });\n\t\t\tthrow new Error('error-room-not-served');\n\t\t}\n\n\t\tconst inquiry = await LivechatInquiry.findOneByRoomId(roomId, {});\n\t\tif (!inquiry) {\n\t\t\tthis.logger.error({ msg: 'No inquiry found for room', roomId });\n\t\t\tthrow new Error('error-invalid-inquiry');\n\t\t}","sourceCodeStart":72,"sourceCodeEnd":108,"githubUrl":"https://github.com/RocketChat/Rocket.Chat/blob/f9d3ec372bb580fa8d036f94cf03925a478ef768/apps/meteor/ee/server/local-services/omnichannel.internalService.ts#L72-L108","documentation":"Thrown by resumeRoomOnHold when `room.open` is false. You cannot resume a held chat that is already closed, because closing terminates the conversation. This guard precedes the onHold check.","triggerScenarios":"Calling resumeRoomOnHold for a room whose `open` is false — a chat that was closed (agent closed it, visitor left, abandonment timeout) while it happened to also be on hold.","commonSituations":"A held chat expires and auto-closes, then an agent clicks Resume; the UI still lists the held chat after a close event; concurrent close + resume.","solutions":["Filter the held-chats list by open === true so closed rooms never offer a Resume action.","Refresh the room before resume and tell the user the chat is closed if room.open is false.","Check the close-on-hold timeout settings if held rooms are closing unexpectedly."],"exampleFix":"// before\nawait omnichannelService.resumeRoomOnHold(room, comment, user);\n\n// after\nif (!room.open) {\n  throw new Error('This conversation is already closed');\n}\nawait omnichannelService.resumeRoomOnHold(room, comment, user);","handlingStrategy":"validation","validationCode":"if (!room.open) throw new Error('This conversation is already closed');\nawait omnichannelService.resumeRoomOnHold(room, comment, user);","typeGuard":"function isOpenRoom(room: unknown): boolean {\n  return !!room && (room as any).open === true;\n}","tryCatchPattern":"try {\n  await omnichannelService.resumeRoomOnHold(room, comment, user);\n} catch (e) {\n  if (e instanceof Error && e.message === 'This_conversation_is_already_closed') {\n    notifyUser('This conversation is already closed.');\n    return;\n  }\n  throw e;\n}","preventionTips":["Filter the held-chats list by open === true.","Refresh the room before resume.","Tune close-on-hold timeouts if held rooms close unexpectedly."],"tags":["omnichannel","livechat","room-state","validation"],"backgroundTag":null,"analyzedSha":"f9d3ec372bb580fa8d036f94cf03925a478ef768","analyzedAt":"2026-08-12T19:07:17.372Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}