{"record":{"id":"e58a1f299e1c2eeb","repo":"RocketChat/Rocket.Chat","slug":"param-params-members-key-must-be-an-array-if","errorCode":null,"errorMessage":"Param \"${params.members.key}\" must be an array if provided","messagePattern":"Param \"(.+?)\" must be an array if provided","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"warning","filePath":"apps/meteor/server/api/v1/channels.ts","lineNumber":1022,"sourceCode":"\tteams?: { key: string; value?: string[] };\n\tteamId?: { key: string; value?: string };\n}) {\n\tconst teamId = params.teamId?.value;\n\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>;","sourceCodeStart":1004,"sourceCodeEnd":1040,"githubUrl":"https://github.com/RocketChat/Rocket.Chat/blob/f9d3ec372bb580fa8d036f94cf03925a478ef768/apps/meteor/server/api/v1/channels.ts#L1004-L1040","documentation":"Thrown during channel creation when params.members.value is present but not an array. The check is explicitly 'if provided' - a missing members param is fine; a present-but-wrong-type one is rejected. The param key name is interpolated into the message.","triggerScenarios":"Submitting members as a comma-separated string, a single object, or any non-array value instead of a JSON array of usernames.","commonSituations":"Client serializing members with the wrong content-type or joining them into a string; API consumer passing members: 'user1,user2' instead of members: ['user1','user2'].","solutions":["Send members as a JSON array: members: ['user1', 'user2'].","If accepting CSV input is desired, split it server-side before this check.","Validate the members shape client-side before submission."],"exampleFix":"// before - request body\n{ \"name\": \"room\", \"members\": \"alice,bob\" }\n\n// after\n{ \"name\": \"room\", \"members\": [\"alice\", \"bob\"] }","handlingStrategy":"validation","validationCode":"function normalizeMembers(members) {\n  if (members == null) return undefined;\n  if (typeof members === 'string') return members.split(',').map(s => s.trim()).filter(Boolean);\n  if (Array.isArray(members)) return members;\n  throw new Error('members must be an array');\n}","typeGuard":"function isStringArray(value) {\n  return Array.isArray(value) && value.every(v => typeof v === 'string');\n}","tryCatchPattern":"try {\n  await api.createChannel({ name, members });\n} catch (e) {\n  if (/must be an array/.test(e.message)) {\n    // coerce and retry once\n    members = Array.isArray(members) ? members : [members];\n    return api.createChannel({ name, members });\n  }\n  throw e;\n}","preventionTips":["Always send members as a JSON array of username strings.","Add a client-side schema check (e.g., zod) before submit.","Avoid CSV-style serialization for array params."],"tags":["channels","validation","param-type","create"],"backgroundTag":null,"analyzedSha":"f9d3ec372bb580fa8d036f94cf03925a478ef768","analyzedAt":"2026-08-12T19:07:17.372Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}