{"record":{"id":"50fdba0a7a2ecea7","repo":"RocketChat/Rocket.Chat","slug":"error-not-allowed-to-close-conversation","errorCode":null,"errorMessage":"error-not-allowed-to-close-conversation","messagePattern":"error-not-allowed-to-close-conversation","errorType":"exception","errorClass":"Error","httpStatus":400,"severity":"error","filePath":"apps/meteor/server/api/v1/omnichannel/room.ts","lineNumber":138,"sourceCode":"\t\t\t\tthrow new Error('invalid-room');\n\t\t\t}\n\n\t\t\treturn API.v1.success({ room: froom, newRoom: false });\n\t\t},\n\t},\n);\n\n// Note: use this route if a visitor is closing a room\n// If a RC user(like eg agent) is closing a room, use the `livechat/room.closeByUser` route\nAPI.v1.addRoute(\n\t'livechat/room.close',\n\t{ validateParams: isPOSTLivechatRoomCloseParams },\n\t{\n\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 });","sourceCodeStart":120,"sourceCodeEnd":156,"githubUrl":"https://github.com/RocketChat/Rocket.Chat/blob/b2c16d5842cbe6b69b59bdf6fc5e5f1afcd1f0b0/apps/meteor/server/api/v1/omnichannel/room.ts#L120-L156","documentation":"Thrown by POST /api/v1/livechat/room.close when the server setting Omnichannel_allow_visitors_to_close_conversation is false. This is a configuration gate evaluated before any token/room validation — visitors are simply not permitted to end conversations through this endpoint. Admins/agents must instead use livechat/room.closeByUser, which is user-authenticated.","triggerScenarios":"POST /api/v1/livechat/room.close with { rid, token } on a workspace where the setting is disabled (Administration > Omnichannel > 'Allow visitors to close conversations' off). It fires regardless of token validity, since the check comes first.","commonSituations":"Fresh installs or locked-down enterprise workspaces where admins deliberately keep closure agent-controlled; a widget shipped with a 'close chat' button deployed against a server that disallows visitor closure; settings reset during migration.","solutions":["Enable 'Allow visitors to close conversations' (Omnichannel_allow_visitors_to_close_conversation) in Administration > Workspace > Omnichannel settings if visitors should close chats.","If closure must stay agent-only, hide the visitor close button and use POST /api/v1/livechat/room.closeByUser with an authenticated user and hasPermission for closing.","Have the client read the livechat init settings (visitorsCanCloseChat in GET livechat/config) and only show the close affordance when true."],"exampleFix":"// before (close button always shown)\n<button onClick={() => sdk.post('livechat/room.close', { rid, token })}>End chat</button>\n\n// after (respect the server setting surfaced via livechat config)\nconst { settings } = await (await fetch('/api/v1/livechat/config')).json();\n{settings.visitorsCanCloseChat && (\n  <button onClick={() => sdk.post('livechat/room.close', { rid, token })}>End chat</button>\n)}","handlingStrategy":"validation","validationCode":"// Read the capability from livechat config before showing the close button\nconst cfg = await (await fetch('/api/v1/livechat/config')).json();\nconst visitorsCanClose: boolean = cfg.settings?.visitorsCanCloseChat === true;\nif (visitorsCanClose) renderCloseButton();","typeGuard":null,"tryCatchPattern":"if (isLivechatErrorResponse(body) && body.error === 'error-not-allowed-to-close-conversation') {\n  hideCloseButton(); // server forbids visitor closure; do not retry\n  showNotice('This chat can only be ended by an agent.');\n}","preventionTips":["Gate the UI on the config value (visitorsCanCloseChat), not on a hardcoded assumption.","If your product requires visitor closure, verify the admin setting during deployment smoke tests.","For agent-side closure, use the authenticated livechat/room.closeByUser route instead."],"tags":["livechat","omnichannel","settings","permission","room-close","rest-api"],"backgroundTag":"feature-disabled-by-config","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"}