{"record":{"id":"9e9958471abedfac","repo":"RocketChat/Rocket.Chat","slug":"invalid-room-9e9958","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/saveRoomReadOnly.ts","lineNumber":14,"sourceCode":"import { Message } from '@rocket.chat/core-services';\nimport type { IUser } from '@rocket.chat/core-typings';\nimport { Rooms } from '@rocket.chat/models';\nimport { Match } from 'meteor/check';\nimport { Meteor } from 'meteor/meteor';\n\nexport async function saveRoomReadOnly(\n\trid: string,\n\treadOnly: boolean,\n\tuser: Required<Pick<IUser, '_id' | 'username' | 'name'>>,\n\tsendMessage = true,\n) {\n\tif (!Match.test(rid, String)) {\n\t\tthrow new Meteor.Error('invalid-room', 'Invalid room', {\n\t\t\tfunction: 'RocketChat.saveRoomReadOnly',\n\t\t});\n\t}\n\n\tconst result = await Rooms.setReadOnlyById(rid, readOnly);\n\n\tif (result && sendMessage) {\n\t\tif (readOnly) {\n\t\t\tawait Message.saveSystemMessage('room-set-read-only', rid, '', user);\n\t\t} else {\n\t\t\tawait Message.saveSystemMessage('room-removed-read-only', rid, '', user);\n\t\t}\n\t}\n\treturn result;\n}\n","sourceCodeStart":1,"sourceCodeEnd":30,"githubUrl":"https://github.com/RocketChat/Rocket.Chat/blob/b2c16d5842cbe6b69b59bdf6fc5e5f1afcd1f0b0/apps/meteor/server/lib/rooms/settings/saveRoomReadOnly.ts#L1-L30","documentation":"Thrown by saveRoomReadOnly when Match.test(rid, String) fails (saveRoomReadOnly.ts:14) — the room id is not a string (undefined/null/number/object). Pure argument-type gate ahead of Rooms.setReadOnlyById and the system messages; nothing is modified when it throws. Code 'invalid-room', details { function: 'RocketChat.saveRoomReadOnly' }.","triggerScenarios":"saveRoomReadOnly(undefined, true, user) from an unvalidated method payload; passing room document/ObjectId; variable renamed between roomId and rid leaving one call site broken.","commonSituations":"Channel settings forms with missing hidden rid inputs; REST wrappers forwarding raw body fields; tests using placeholder ids.","solutions":["Pass the room _id string as the first argument","Validate rid at the method/endpoint boundary before calling","Inspect the caller for missing destructuring or wrong property name","Add a lightweight unit test that non-string rid throws 'invalid-room' early"],"exampleFix":"// before\nawait saveRoomReadOnly(body.rid, readOnly, user);\n\n// after\nif (typeof body.rid !== 'string' || body.rid.length === 0) {\n\tthrow new Meteor.Error('invalid-room', 'Invalid room', { function: 'RocketChat.saveRoomReadOnly' });\n}\nawait saveRoomReadOnly(body.rid, readOnly, user);","handlingStrategy":"type-guard","validationCode":"if (typeof rid !== 'string' || rid.length === 0) {\n\tthrow new Meteor.Error('invalid-room', 'Invalid room', { function: 'RocketChat.saveRoomReadOnly' });\n}\nawait saveRoomReadOnly(rid, readOnly, user);","typeGuard":"const isRoomId = (v: unknown): v is string => typeof v === 'string' && v.length > 0;","tryCatchPattern":null,"preventionTips":["Pass room._id as a string; never the document or ObjectId","Validate the method payload once at the boundary","Keep rid naming uniform across settings handlers"],"tags":["room-settings","argument-validation","meteor-check","read-only"],"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"}