{"record":{"id":"195f8a30ff013e29","repo":"RocketChat/Rocket.Chat","slug":"invalid-room-195f8a","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/saveRoomCustomFields.ts","lineNumber":10,"sourceCode":"import { 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 saveRoomCustomFields = async function (rid: string, roomCustomFields: Record<string, any>): Promise<UpdateResult> {\n\tif (!Match.test(rid, String)) {\n\t\tthrow new Meteor.Error('invalid-room', 'Invalid room', {\n\t\t\tfunction: 'RocketChat.saveRoomCustomFields',\n\t\t});\n\t}\n\n\tif (!Match.test(roomCustomFields, Object)) {\n\t\tthrow new Meteor.Error('invalid-roomCustomFields-type', 'Invalid roomCustomFields type', {\n\t\t\tfunction: 'RocketChat.saveRoomCustomFields',\n\t\t});\n\t}\n\n\tconst ret = await Rooms.setCustomFieldsById(rid, roomCustomFields);\n\n\t// Update customFields of any user's Subscription related with this rid\n\tconst { modifiedCount } = await Subscriptions.updateCustomFieldsByRoomId(rid, roomCustomFields);\n\tif (modifiedCount) {\n\t\tvoid notifyOnSubscriptionChangedByRoomId(rid);\n\t}\n","sourceCodeStart":1,"sourceCodeEnd":28,"githubUrl":"https://github.com/RocketChat/Rocket.Chat/blob/b2c16d5842cbe6b69b59bdf6fc5e5f1afcd1f0b0/apps/meteor/server/lib/rooms/settings/saveRoomCustomFields.ts#L1-L28","documentation":"Thrown by saveRoomCustomFields when Match.test(rid, String) fails (saveRoomCustomFields.ts:10). First of two guards in this function: it only checks that rid is a string; the customFields payload is validated separately on the next lines. Code 'invalid-room', details { function: 'RocketChat.saveRoomCustomFields' }.","triggerScenarios":"saveRoomCustomFields(undefined, fields); rid from a wrong destructuring ({ rid: id }); passing a room object; numeric id from an external sync tool.","commonSituations":"Apps-engine or REST integrations mapping room identifiers incorrectly; bulk scripts iterating rows where some rows lack the room id column.","solutions":["Ensure the first argument is the room _id string","Filter/validate rows in bulk scripts before invoking (skip rows without a valid rid)","Add a boundary check in the calling method: if (typeof rid !== 'string') return badRequest","Remember this function has a second guard ('invalid-roomCustomFields-type') — fix both argument types at once"],"exampleFix":"// before\nawait saveRoomCustomFields(body.rid, body.fields); // body.rid missing on some payloads\n\n// after\nif (typeof body.rid !== 'string') {\n\tthrow new Meteor.Error('invalid-room', 'Invalid room');\n}\nawait saveRoomCustomFields(body.rid, body.fields ?? {});","handlingStrategy":"type-guard","validationCode":"if (typeof rid !== 'string' || rid.length === 0) {\n\tthrow new Meteor.Error('invalid-room', 'Invalid room', { function: 'RocketChat.saveRoomCustomFields' });\n}\nawait saveRoomCustomFields(rid, customFields);","typeGuard":"const isRoomId = (v: unknown): v is string => typeof v === 'string' && v.length > 0;","tryCatchPattern":null,"preventionTips":["Skip bulk rows lacking a valid rid before calling","Validate both rid (string) and customFields (plain object) at once","Log rejected rows so partial input is visible"],"tags":["room-settings","argument-validation","meteor-check","custom-fields"],"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"}