{"record":{"id":"23a20d6aa1d0fed1","repo":"RocketChat/Rocket.Chat","slug":"invalid-roomcustomfields-type","errorCode":"invalid-roomCustomFields-type","errorMessage":"Invalid roomCustomFields type","messagePattern":"Invalid roomCustomFields type","errorType":"exception","errorClass":"Meteor.Error","httpStatus":null,"severity":"error","filePath":"apps/meteor/server/lib/rooms/settings/saveRoomCustomFields.ts","lineNumber":16,"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\n\treturn ret;\n};\n","sourceCodeStart":1,"sourceCodeEnd":31,"githubUrl":"https://github.com/RocketChat/Rocket.Chat/blob/b2c16d5842cbe6b69b59bdf6fc5e5f1afcd1f0b0/apps/meteor/server/lib/rooms/settings/saveRoomCustomFields.ts#L1-L31","documentation":"Thrown by saveRoomCustomFields when Match.test(roomCustomFields, Object) fails (saveRoomCustomFields.ts:16). In Meteor's check semantics, Object matches plain objects only — null, undefined, primitives, and arrays all fail. Code 'invalid-roomCustomFields-type', details { function: 'RocketChat.saveRoomCustomFields' }.","triggerScenarios":"Passing null/undefined defaults (fields ?? null); passing an array of key/value pairs instead of a map; passing a JSON string that was never parsed (typeof 'string'); body-parsers returning a primitive for empty payloads.","commonSituations":"REST integrations sending application/x-www-form-urlencoded where customFields arrives as a string; code doing JSON.stringify at the caller but forgetting JSON.parse at the callee; treating an empty payload as null instead of {}.","solutions":["Pass a plain object, defaulting to {} when there is nothing to set","Parse before calling: typeof fields === 'string' ? JSON.parse(fields) : fields","Reject arrays at the boundary — they are not valid custom-fields maps","Match on code 'invalid-roomCustomFields-type' to report a payload problem rather than a room problem"],"exampleFix":"// before\nawait saveRoomCustomFields(rid, body.customFields); // arrives as '{\"dept\":\"sales\"}' string\n\n// after\nconst customFields = typeof body.customFields === 'string' ? JSON.parse(body.customFields) : body.customFields ?? {};\nawait saveRoomCustomFields(rid, customFields);","handlingStrategy":"type-guard","validationCode":"const isPlainObject = (v: unknown): v is Record<string, unknown> =>\n\ttypeof v === 'object' && v !== null && !Array.isArray(v);\nif (!isPlainObject(customFields)) {\n\tthrow new Meteor.Error('invalid-roomCustomFields-type', 'Invalid roomCustomFields type');\n}\nawait saveRoomCustomFields(rid, customFields);","typeGuard":"const isPlainObject = (v: unknown): v is Record<string, unknown> =>\n\ttypeof v === 'object' && v !== null && !Array.isArray(v);","tryCatchPattern":null,"preventionTips":["Default missing payloads to {} not null","JSON.parse string payloads before calling","Remember Meteor's Object pattern rejects arrays and null"],"tags":["room-settings","custom-fields","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"}