{"record":{"id":"b4b1ad0c59b0a3ed","repo":"RocketChat/Rocket.Chat","slug":"invalid-room-b4b1ad","errorCode":null,"errorMessage":"invalid-room","messagePattern":"invalid-room","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"apps/meteor/server/api/v1/omnichannel/message.ts","lineNumber":38,"sourceCode":"import { settings } from '../../../settings';\nimport { getPaginationItems } from '../../lib/getPaginationItems';\nimport { isWidget } from '../../lib/isWidget';\n\nAPI.v1.addRoute(\n\t'livechat/message',\n\t{ validateParams: isPOSTLivechatMessageParams },\n\t{\n\t\tasync post() {\n\t\t\tconst { token, rid, agent, msg } = this.bodyParams;\n\n\t\t\tconst guest = await findGuest(token);\n\t\t\tif (!guest) {\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\tif (\n\t\t\t\tsettings.get('Livechat_enable_message_character_limit') &&\n\t\t\t\tmsg.length > parseInt(settings.get('Livechat_message_character_limit'))\n\t\t\t) {\n\t\t\t\tthrow new Error('message-length-exceeds-character-limit');\n\t\t\t}\n\n\t\t\tconst _id = this.bodyParams._id || Random.id();\n\n\t\t\tconst messageToSend = {\n\t\t\t\tguest,\n\t\t\t\tmessage: {","sourceCodeStart":20,"sourceCodeEnd":56,"githubUrl":"https://github.com/RocketChat/Rocket.Chat/blob/f9d3ec372bb580fa8d036f94cf03925a478ef768/apps/meteor/server/api/v1/omnichannel/message.ts#L20-L56","documentation":"Thrown by POST /livechat/message (message.ts:36-39) when findRoom(token, rid) returns null. findRoom (livechat.ts:59-74) looks the room up by id AND visitor token (findOneByIdAndVisitorToken), so null means either the room does not exist or it does not belong to the visitor owning `token`. Returns HTTP 400 { success:false, error:'invalid-room' }.","triggerScenarios":"POST /livechat/message with a rid that does not exist, belongs to a different visitor/token, or is the wrong kind of id.","commonSituations":"Reused rid after visitor re-registration (new token no longer matches the old room); typo; passing the room name or a messageId as rid.","solutions":["Ensure rid belongs to the visitor that owns `token` (use the rid returned by room creation).","Pre-verify with findRoom(token, rid); if null, create/open a new room for the visitor.","Confirm rid is the livechat room `_id`, not its name or a message id."],"exampleFix":"// before\nPOST /livechat/message { token, rid: cachedRid, msg } // throws invalid-room after re-register\n\n// after\nconst room = await findRoom(token, rid);\nif (!room) { /* open a new room for this visitor first */ }\nPOST /livechat/message { token, rid: room._id, msg }","handlingStrategy":"validation","validationCode":"const room = await findRoom(token, rid);\nif (!room) {\n  // open a new room for this visitor, then retry\n  throw new Error('room not found for this visitor token');\n}\n// safe to POST /livechat/message","typeGuard":"const roomBelongsToVisitor = async (token: string, rid: string) =>\n  !!(await LivechatRooms.findOneByIdAndVisitorToken(rid, token, { projection: { _id: 1 } }));","tryCatchPattern":"try { await sendMessage({ token, rid, msg }); }\ncatch (e) { if (e instanceof Error && e.message === 'invalid-room') { /* open new room, retry */ } else throw e; }","preventionTips":["Keep token and rid as a pair from the same session.","After re-registering a visitor, open a fresh room rather than reusing an old rid."],"tags":["livechat","omnichannel","room","visitor-token","messaging"],"backgroundTag":null,"analyzedSha":"f9d3ec372bb580fa8d036f94cf03925a478ef768","analyzedAt":"2026-08-12T19:07:17.372Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}