{"record":{"id":"2fd773dcd00a9dce","repo":"RocketChat/Rocket.Chat","slug":"param-params-teams-key-must-be-an-array","errorCode":null,"errorMessage":"Param ${params.teams.key} must be an array","messagePattern":"Param (.+?) must be an array","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"warning","filePath":"apps/meteor/server/api/v1/channels.ts","lineNumber":1030,"sourceCode":"\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 }> {\n\tconst readOnly = typeof params.readOnly !== 'undefined' ? params.readOnly : false;\n\tconst id = await createChannelMethod(\n\t\tuserId,\n\t\tparams.name || '',","sourceCodeStart":1012,"sourceCodeEnd":1048,"githubUrl":"https://github.com/RocketChat/Rocket.Chat/blob/f9d3ec372bb580fa8d036f94cf03925a478ef768/apps/meteor/server/api/v1/channels.ts#L1012-L1048","documentation":"Thrown during channel creation when params.teams.value is present but not an array. Unlike the members message, this one omits the 'if provided' phrasing and uses inconsistent quoting (no surrounding quotes around the key) - a minor message inconsistency. The param key is interpolated.","triggerScenarios":"Submitting teams as a single team ID string or an object instead of an array of team identifiers.","commonSituations":"Client sending teams: 'teamId123' instead of teams: ['teamId123']; migration script reusing a scalar team field for the new array param.","solutions":["Send teams as a JSON array, even for a single team: teams: ['teamId123'].","Validate the teams param shape client-side before submission.","Normalize the message to match the members style (quote the key) if you own the code."],"exampleFix":"// before - request body\n{ \"name\": \"room\", \"teams\": \"generalTeam\" }\n\n// after\n{ \"name\": \"room\", \"teams\": [\"generalTeam\"] }","handlingStrategy":"validation","validationCode":"function normalizeTeams(teams) {\n  if (teams == null) return undefined;\n  if (typeof teams === 'string') return [teams];\n  if (Array.isArray(teams)) return teams;\n  throw new Error('teams 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, teams });\n} catch (e) {\n  if (/must be an array/.test(e.message)) {\n    teams = Array.isArray(teams) ? teams : [teams];\n    return api.createChannel({ name, teams });\n  }\n  throw e;\n}","preventionTips":["Always send teams as an array even for one team.","Normalize scalar team ids to arrays at the API client boundary.","Validate the param shape with a client-side schema."],"tags":["channels","validation","param-type","teams","create"],"backgroundTag":null,"analyzedSha":"f9d3ec372bb580fa8d036f94cf03925a478ef768","analyzedAt":"2026-08-12T19:07:17.372Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}