{"record":{"id":"08500d6c95417632","repo":"RocketChat/Rocket.Chat","slug":"param-params-customfields-key-must-be-an-obje","errorCode":null,"errorMessage":"Param \"${params.customFields.key}\" must be an object if provided","messagePattern":"Param \"(.+?)\" must be an object if provided","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"apps/meteor/server/api/v1/channels.ts","lineNumber":1027,"sourceCode":"\n\tconst team = teamId && (await Team.getInfoById(teamId));\n\tif (\n\t\t(!teamId && !(await hasPermissionAsync(params.user.value, 'create-c'))) ||\n\t\t(teamId && team && !(await hasPermissionAsync(params.user.value, 'create-team-channel', team.roomId)))\n\t) {\n\t\tthrow new Error('unauthorized');\n\t}\n\n\tif (!params.name?.value) {\n\t\tthrow new Error(`Param \"${params.name?.key}\" is required`);\n\t}\n\n\tif (params.members?.value && !Array.isArray(params.members.value)) {\n\t\tthrow new Error(`Param \"${params.members.key}\" must be an array if provided`);\n\t}\n\n\tif (params.customFields?.value && !(typeof params.customFields.value === 'object')) {\n\t\tthrow new Error(`Param \"${params.customFields.key}\" must be an object if provided`);\n\t}\n\n\tif (params.teams?.value && !Array.isArray(params.teams.value)) {\n\t\tthrow new Error(`Param ${params.teams.key} must be an array`);\n\t}\n}\n\nasync function createChannel(\n\tuserId: string,\n\tparams: {\n\t\tname?: string;\n\t\tmembers?: string[];\n\t\tcustomFields?: Record<string, any>;\n\t\textraData?: Record<string, any>;\n\t\treadOnly?: boolean;\n\t\texcludeSelf?: boolean;\n\t},\n): Promise<{ channel: IRoom }> {","sourceCodeStart":1009,"sourceCodeEnd":1045,"githubUrl":"https://github.com/RocketChat/Rocket.Chat/blob/e4b8178b205510181a96ceefee043d0abcd13e5a/apps/meteor/server/api/v1/channels.ts#L1009-L1045","documentation":"Validation error from POST channels.create: customFields was supplied but is not a plain object (map of field name to value). The API stores arbitrary custom fields keyed by name, so anything not typeof 'object' — a JSON string, array, or scalar — is rejected. Note this check does not validate against the custom fields configured in admin settings; that happens later in the create pipeline.","triggerScenarios":"POST /api/v1/channels.create with customFields: \"{\\\"dept\\\":\\\"sales\\\"}\" (double-encoded JSON string) or customFields: [\"dept\"] instead of customFields: {\"dept\":\"sales\"}.","commonSituations":"Double-serialized JSON when a client stringifies the body twice; passing an array of key/value pairs from a form; forgetting to define the custom field in Administration > Rooms (custom fields must also be declared there or they are stripped later).","solutions":["Send customFields as a plain JSON object: {\"field\":\"value\"}","JSON.parse once if the value arrives as a string before putting it in the body","Declare allowed custom fields in Administration > Settings > Rooms, otherwise they are dropped even when the shape is valid"],"exampleFix":"// before\n{ \"name\": \"dev-talk\", \"customFields\": \"{\\\"dept\\\":\\\"sales\\\"}\" }\n\n// after\n{ \"name\": \"dev-talk\", \"customFields\": { \"dept\": \"sales\" } }","handlingStrategy":"type-guard","validationCode":"if (typeof body.customFields === 'string') {\n  body.customFields = JSON.parse(body.customFields); // fix double-encoded JSON\n}\nif (body.customFields !== undefined && typeof body.customFields !== 'object') {\n  throw new Error('customFields must be an object');\n}","typeGuard":"const isCustomFieldsObject = (c: unknown): c is Record<string, unknown> =>\n  typeof c === 'object' && c !== null && !Array.isArray(c);","tryCatchPattern":"try { await POST('/api/v1/channels.create', body); } catch (e) {\n  if (/customFields.*must be an object/.test(e.message)) { /* send plain object */ }\n}","preventionTips":["Never JSON.stringify the customFields value separately from the body","Declare the custom field in admin settings or it will be stripped downstream"],"tags":["rest-api","channels","validation","custom-fields","rocket-chat"],"backgroundTag":"parameter-type-mismatch","analyzedSha":"e4b8178b205510181a96ceefee043d0abcd13e5a","analyzedAt":"2026-08-18T15:26:39.429Z","contentChangedAt":"2026-08-18T15:26:39.429Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}