{"record":{"id":"ce66d110c9f197cc","repo":"RocketChat/Rocket.Chat","slug":"invalid-room-ce66d1","errorCode":"invalid-room","errorMessage":"Invalid room","messagePattern":"Invalid room","errorType":"exception","errorClass":"Meteor.Error","httpStatus":null,"severity":"error","filePath":"apps/meteor/server/lib/rooms/settings/saveRoomEncrypted.ts","lineNumber":13,"sourceCode":"import { Message } from '@rocket.chat/core-services';\nimport type { IUser } from '@rocket.chat/core-typings';\nimport { isRegisterUser } from '@rocket.chat/core-typings';\nimport { Rooms, Subscriptions } from '@rocket.chat/models';\nimport { Match } from 'meteor/check';\nimport { Meteor } from 'meteor/meteor';\nimport type { UpdateResult } from 'mongodb';\n\nimport { notifyOnSubscriptionChangedByRoomId } from '../../notifyListener';\n\nexport const saveRoomEncrypted = async function (rid: string, encrypted: boolean, user: IUser, sendMessage = true): Promise<UpdateResult> {\n\tif (!Match.test(rid, String)) {\n\t\tthrow new Meteor.Error('invalid-room', 'Invalid room', {\n\t\t\tfunction: 'RocketChat.saveRoomEncrypted',\n\t\t});\n\t}\n\n\tif (!isRegisterUser(user)) {\n\t\tthrow new Meteor.Error('invalid-user', 'Invalid user', {\n\t\t\tfunction: 'RocketChat.saveRoomEncrypted',\n\t\t});\n\t}\n\n\tconst update = await Rooms.saveEncryptedById(rid, encrypted);\n\tif (update && sendMessage) {\n\t\tconst type = encrypted ? 'room_e2e_enabled' : 'room_e2e_disabled';\n\n\t\tawait Message.saveSystemMessage(type, rid, user.username, user);\n\t}\n\n\tif (encrypted) {","sourceCodeStart":1,"sourceCodeEnd":31,"githubUrl":"https://github.com/RocketChat/Rocket.Chat/blob/b2c16d5842cbe6b69b59bdf6fc5e5f1afcd1f0b0/apps/meteor/server/lib/rooms/settings/saveRoomEncrypted.ts#L1-L31","documentation":"Thrown by saveRoomEncrypted when Match.test(rid, String) fails (saveRoomEncrypted.ts:13). First guard of the function; a second guard ('invalid-user') validates the user right after. Nothing is persisted when it throws. Code 'invalid-room', details { function: 'RocketChat.saveRoomEncrypted' }.","triggerScenarios":"Calling saveRoomEncrypted with a rid that is undefined/number/room document; e2e toggle handler receiving a bad room id from the client; passing ObjectId instead of string.","commonSituations":"E2E toggle UI sending stale room ids after the room closed; federation/app code building rid from parts and occasionally producing undefined.","solutions":["Pass the room _id string as the first argument","Validate rid before calling and return an explicit bad-request from the handler","Check the client payload for the e2e toggle if this surfaces via a meteor method","Fix the user guard too if the same call passes partial users (next check is isRegisterUser)"],"exampleFix":"// before\nawait saveRoomEncrypted(body.rid, body.encrypted, user);\n\n// after\nif (typeof body.rid !== 'string') {\n\tthrow new Meteor.Error('invalid-room', 'Invalid room', { function: 'RocketChat.saveRoomEncrypted' });\n}\nawait saveRoomEncrypted(body.rid, body.encrypted, user);","handlingStrategy":"type-guard","validationCode":"if (typeof rid !== 'string' || rid.length === 0) {\n\tthrow new Meteor.Error('invalid-room', 'Invalid room', { function: 'RocketChat.saveRoomEncrypted' });\n}\nawait saveRoomEncrypted(rid, encrypted, user);","typeGuard":"const isRoomId = (v: unknown): v is string => typeof v === 'string' && v.length > 0;","tryCatchPattern":null,"preventionTips":["Have the e2e toggle client send the current room._id from live room data","Validate rid AND isRegisterUser(user) together for this function","Return 400 early from method handlers on malformed payloads"],"tags":["room-settings","e2e-encryption","argument-validation","meteor-check"],"backgroundTag":"invalid-argument-value","analyzedSha":"b2c16d5842cbe6b69b59bdf6fc5e5f1afcd1f0b0","analyzedAt":"2026-08-18T15:26:39.429Z","contentChangedAt":"2026-08-18T15:26:39.429Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}