{"record":{"id":"298e9a52e1f672c0","repo":"RocketChat/Rocket.Chat","slug":"room-closed-298e9a","errorCode":"room-closed","errorMessage":"room-closed","messagePattern":"room-closed","errorType":"exception","errorClass":"Error","httpStatus":400,"severity":"error","filePath":"apps/meteor/server/api/v1/omnichannel/room.ts","lineNumber":152,"sourceCode":"\t\tasync post() {\n\t\t\tconst { rid, token } = this.bodyParams;\n\n\t\t\tif (!rcSettings.get('Omnichannel_allow_visitors_to_close_conversation')) {\n\t\t\t\tthrow new Error('error-not-allowed-to-close-conversation');\n\t\t\t}\n\n\t\t\tconst visitor = await findGuest(token);\n\t\t\tif (!visitor) {\n\t\t\t\tthrow new Error('invalid-token');\n\t\t\t}\n\n\t\t\tconst room = await findRoom(token, rid);\n\t\t\tif (!room) {\n\t\t\t\tthrow new 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\tconst language = rcSettings.get<string>('Language') || 'en';\n\t\t\tconst comment = i18n.t('Closed_by_visitor', { lng: language });\n\n\t\t\tconst options: CloseRoomParams['options'] = {};\n\t\t\tif (room.servedBy) {\n\t\t\t\tconst servingAgent: Pick<IUser, '_id' | 'name' | 'username' | 'utcOffset' | 'settings' | 'language'> | null =\n\t\t\t\t\tawait Users.findOneById(room.servedBy._id, {\n\t\t\t\t\t\tprojection: {\n\t\t\t\t\t\t\tname: 1,\n\t\t\t\t\t\t\tusername: 1,\n\t\t\t\t\t\t\tutcOffset: 1,\n\t\t\t\t\t\t\tsettings: 1,\n\t\t\t\t\t\t\tlanguage: 1,\n\t\t\t\t\t\t},\n\t\t\t\t\t});\n","sourceCodeStart":134,"sourceCodeEnd":170,"githubUrl":"https://github.com/RocketChat/Rocket.Chat/blob/f9d3ec372bb580fa8d036f94cf03925a478ef768/apps/meteor/server/api/v1/omnichannel/room.ts#L134-L170","documentation":"Thrown in the POST handler of 'livechat/room.close' (room.ts:151-153) when room.open is false. After successfully finding the room by token and rid, the handler checks whether the room is still open. If the room has already been closed (by visitor, agent, or system), room.open is false and this error fires.","triggerScenarios":"Calling POST /api/v1/livechat/room.close for a room that is already in a closed state. This can happen on a double-close attempt or when an agent closed the room between the client's last status check and the close request.","commonSituations":"Visitor clicks close twice (double-submit); agent closed the room concurrently; the room was auto-closed by an inactivity timeout or system process; the client didn't refresh room state after a previous close.","solutions":["Check the room's open status before attempting to close: db.livechat_rooms.findOne({_id: rid}, {open: 1}).","If already closed, treat it as a no-op success — the desired end state is achieved.","Disable the close button client-side after the first successful close to prevent double-submits."],"exampleFix":"// before\nawait api.post('/livechat/room.close', { rid, token });\n// throws 'room-closed' on second click\n\n// after — guard against double-close client-side\nif (roomAlreadyClosed) {\n  return { success: true, message: 'Room already closed' };\n}\nawait api.post('/livechat/room.close', { rid, token });","handlingStrategy":"type-guard","validationCode":"// Check room.open before attempting to close\nconst room = await LivechatRooms.findOneByIdAndVisitorToken(rid, token);\nif (room && !room.open) {\n  // already closed — no action needed\n  return { success: true, reason: 'already-closed' };\n}","typeGuard":"function isRoomOpen(room: IOmnichannelRoom | null): room is IOmnichannelRoom {\n  return room !== null && room.open === true;\n}","tryCatchPattern":"try {\n  await api.post('/livechat/room.close', { rid, token });\n} catch (err) {\n  if (err.message === 'room-closed') {\n    // already closed — treat as success\n    return { success: true };\n  }\n}","preventionTips":["Check room.open status before calling room.close to avoid double-close.","Disable the close button client-side immediately after the first click to prevent double-submits.","Treat 'room-closed' as an idempotent success in client error handling."],"tags":["omnichannel","room","closed-room","state","room"],"backgroundTag":null,"analyzedSha":"f9d3ec372bb580fa8d036f94cf03925a478ef768","analyzedAt":"2026-08-12T19:07:17.372Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}