{"record":{"id":"fe50b87e122da6c9","repo":"RocketChat/Rocket.Chat","slug":"unauthorized","errorCode":null,"errorMessage":"unauthorized","messagePattern":"unauthorized","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"apps/meteor/server/api/v1/channels.ts","lineNumber":1014,"sourceCode":"\t},\n);\n\nasync function createChannelValidator(params: {\n\tuser: { value: string };\n\tname?: { key: string; value?: string };\n\tmembers?: { key: string; value?: string[] };\n\tcustomFields?: { key: string; value?: string };\n\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}","sourceCodeStart":996,"sourceCodeEnd":1032,"githubUrl":"https://github.com/RocketChat/Rocket.Chat/blob/f9d3ec372bb580fa8d036f94cf03925a478ef768/apps/meteor/server/api/v1/channels.ts#L996-L1032","documentation":"Thrown by the channel-creation permission check before any param validation. Two branches: without a teamId the caller needs the 'create-c' permission; with a teamId the caller needs 'create-team-channel' on the team's room. If teamId is supplied but the team lookup fails (team is falsy), the second condition short-circuits to unauthorized. This is a plain Error, not a Meteor.Error.","triggerScenarios":"A user without 'create-c' calls the create-channel endpoint without a teamId; or a user without 'create-team-channel' tries to create a team channel; or a teamId is supplied that does not resolve to a team (so the permission branch evaluates against undefined).","commonSituations":"Custom role missing the create-c permission; teamId copied from a deleted team; role scope misconfiguration after a workspace migration.","solutions":["Grant the 'create-c' permission (or 'create-team-channel' scoped to the team) to the user's role in Administration > Permissions.","Validate that teamId resolves to an existing team before calling create, so the permission check runs against a real scope.","Confirm the authenticated user matches the role you expect (check this.user roles)."],"exampleFix":"// before\nif (\n  (!teamId && !(await hasPermissionAsync(params.user.value, 'create-c'))) ||\n  (teamId && team && !(await hasPermissionAsync(params.user.value, 'create-team-channel', team.roomId)))\n) {\n  throw new Error('unauthorized');\n}\n\n// after - explicit, distinguishable failure reasons\nif (!teamId && !(await hasPermissionAsync(params.user.value, 'create-c'))) {\n  throw new Meteor.Error('error-no-create-c-permission', 'User lacks create-c permission');\n}\nif (teamId && !team) {\n  throw new Meteor.Error('error-team-not-found', 'The provided teamId does not match a team');\n}\nif (teamId && team && !(await hasPermissionAsync(params.user.value, 'create-team-channel', team.roomId))) {\n  throw new Meteor.Error('error-no-create-team-channel-permission', 'User lacks create-team-channel permission for this team');\n}","handlingStrategy":"validation","validationCode":"// Verify permissions and team existence before creating a channel\nasync function canCreateChannel(user, teamId) {\n  if (!teamId) {\n    return hasPermissionAsync(user._id, 'create-c');\n  }\n  const team = await Team.getInfoById(teamId);\n  if (!team) return { ok: false, reason: 'team-not-found' };\n  return { ok: await hasPermissionAsync(user._id, 'create-team-channel', team.roomId) };\n}","typeGuard":"function hasCreatePermissionFlags(perms) {\n  return Array.isArray(perms) && (perms.includes('create-c') || perms.includes('create-team-channel'));\n}","tryCatchPattern":"try {\n  await api.createChannel({ name, members, teamId });\n} catch (e) {\n  if (e.message === 'unauthorized') {\n    notifyAdmin('Missing create-c or create-team-channel permission');\n    return;\n  }\n  throw e;\n}","preventionTips":["Grant 'create-c' (or 'create-team-channel' scoped to the team) before exposing create UI.","Validate teamId resolves to a real team so the permission check is meaningful.","Confirm the calling user's role and scope in tests."],"tags":["channels","authorization","permissions","teams","create"],"backgroundTag":null,"analyzedSha":"f9d3ec372bb580fa8d036f94cf03925a478ef768","analyzedAt":"2026-08-12T19:07:17.372Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}