{"record":{"id":"d2c523610c34d9ac","repo":"RocketChat/Rocket.Chat","slug":"invalid-room","errorCode":null,"errorMessage":"invalid-room","messagePattern":"invalid-room","errorType":"exception","errorClass":"Error","httpStatus":400,"severity":"error","filePath":"apps/meteor/server/api/v1/omnichannel/agent.ts","lineNumber":33,"sourceCode":"import { findRoom, findGuest, findAgent, findOpenRoom } from './lib/livechat';\nimport { hasPermissionAsync } from '../../../lib/authorization/hasPermission';\nimport { hasRoleAsync } from '../../../lib/authorization/hasRole';\nimport { RoutingManager } from '../../../lib/omnichannel/RoutingManager';\nimport { getRequiredDepartment } from '../../../lib/omnichannel/departmentsLib';\nimport { saveAgentInfo } from '../../../lib/omnichannel/omni-users';\nimport { setUserStatusLivechat, allowAgentChangeServiceStatus } from '../../../lib/omnichannel/utils';\nimport type { ExtractRoutesFromAPI } from '../../ApiClass';\n\nAPI.v1.addRoute('livechat/agent.info/:rid/:token', {\n\tasync get() {\n\t\tconst visitor = await findGuest(this.urlParams.token);\n\t\tif (!visitor) {\n\t\t\tthrow new Error('invalid-token');\n\t\t}\n\n\t\tconst room = await findRoom(this.urlParams.token, this.urlParams.rid);\n\t\tif (!room) {\n\t\t\tthrow new Error('invalid-room');\n\t\t}\n\n\t\tconst agent = room?.servedBy && (await findAgent(room.servedBy._id));\n\t\tif (!agent) {\n\t\t\tthrow new Error('invalid-agent');\n\t\t}\n\n\t\treturn API.v1.success({ agent });\n\t},\n});\n\nAPI.v1.addRoute(\n\t'livechat/agent.next/:token',\n\t{ validateParams: isGETAgentNextToken },\n\t{\n\t\tasync get() {\n\t\t\tconst { token } = this.urlParams;\n\t\t\tconst room = await findOpenRoom(token, undefined, this.userId);","sourceCodeStart":15,"sourceCodeEnd":51,"githubUrl":"https://github.com/RocketChat/Rocket.Chat/blob/b2c16d5842cbe6b69b59bdf6fc5e5f1afcd1f0b0/apps/meteor/server/api/v1/omnichannel/agent.ts#L15-L51","documentation":"Second guard on GET /api/v1/livechat/agent.info/:rid/:token: findRoom(token, rid) resolves to LivechatRooms.findOneByIdAndVisitorToken(rid, token) (apps/meteor/server/api/v1/omnichannel/lib/livechat.ts:59-74). It returns null - and the route throws Error('invalid-room') at agent.ts:33 - when no omnichannel room exists with that _id, or the room exists but does not belong to the visitor holding that token.","triggerScenarios":"rid typo'd or truncated; rid belonging to another visitor's conversation; room deleted after the conversation ended; token from one session combined with rid from another.","commonSituations":"Widgets caching a stale rid after the conversation was closed/removed; hand-built URLs mixing values from different sessions; environment migrations that copied rooms but not the visitor-token linkage.","solutions":["Use the rid returned together with the token by the livechat session endpoints (e.g. livechat/room) so the pair is always consistent","If the conversation was deleted, start a new session to obtain a fresh rid","Verify the room exists with an agent-side lookup (rooms.info with an authenticated agent token) when debugging"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"const { room } = await fetch(`${server}/api/v1/livechat/room?token=${encodeURIComponent(token)}`).then((r) => r.json());\nif (!room?._id || room._id !== rid) {\n  throw new Error(`rid ${rid} does not belong to this visitor token - use the rid from the current session`);\n}\nawait fetch(`${server}/api/v1/livechat/agent.info/${rid}/${token}`);","typeGuard":"const isRoomOfVisitor = (room: { _id?: string; v?: { token?: string } } | null, rid: string, token: string): room is { _id: string; v: { token: string } } =>\n  !!room && room._id === rid && room.v?.token === token;","tryCatchPattern":"try {\n  const res = await fetch(`${server}/api/v1/livechat/agent.info/${rid}/${token}`);\n  if (!res.ok) throw await res.json();\n} catch (err) {\n  if (err?.error === 'invalid-room') {\n    // token was valid (invalid-token would have fired first): the rid is wrong or stale\n    session = await startNewLivechatSession(); // fetch a fresh rid paired with the token\n  }\n}","preventionTips":["Always take rid from the same response that gave you the token (livechat/room), never from cache","When a conversation can be deleted server-side, design the client to recover by starting a new session on invalid-room"],"tags":["livechat","omnichannel","rest-api","rooms","not-found"],"backgroundTag":"room-not-found","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"}