RocketChat/Rocket.Chat · error · Error
unauthorized
Error message
unauthorized
What it means
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.
Source
Thrown at apps/meteor/server/api/v1/channels.ts:1014
},
);
async function createChannelValidator(params: {
user: { value: string };
name?: { key: string; value?: string };
members?: { key: string; value?: string[] };
customFields?: { key: string; value?: string };
teams?: { key: string; value?: string[] };
teamId?: { key: string; value?: string };
}) {
const teamId = params.teamId?.value;
const team = teamId && (await Team.getInfoById(teamId));
if (
(!teamId && !(await hasPermissionAsync(params.user.value, 'create-c'))) ||
(teamId && team && !(await hasPermissionAsync(params.user.value, 'create-team-channel', team.roomId)))
) {
throw new Error('unauthorized');
}
if (!params.name?.value) {
throw new Error(`Param "${params.name?.key}" is required`);
}
if (params.members?.value && !Array.isArray(params.members.value)) {
throw new Error(`Param "${params.members.key}" must be an array if provided`);
}
if (params.customFields?.value && !(typeof params.customFields.value === 'object')) {
throw new Error(`Param "${params.customFields.key}" must be an object if provided`);
}
if (params.teams?.value && !Array.isArray(params.teams.value)) {
throw new Error(`Param ${params.teams.key} must be an array`);
}
}View on GitHub (pinned to f9d3ec372b)
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).
Example fix
// before
if (
(!teamId && !(await hasPermissionAsync(params.user.value, 'create-c'))) ||
(teamId && team && !(await hasPermissionAsync(params.user.value, 'create-team-channel', team.roomId)))
) {
throw new Error('unauthorized');
}
// after - explicit, distinguishable failure reasons
if (!teamId && !(await hasPermissionAsync(params.user.value, 'create-c'))) {
throw new Meteor.Error('error-no-create-c-permission', 'User lacks create-c permission');
}
if (teamId && !team) {
throw new Meteor.Error('error-team-not-found', 'The provided teamId does not match a team');
}
if (teamId && team && !(await hasPermissionAsync(params.user.value, 'create-team-channel', team.roomId))) {
throw new Meteor.Error('error-no-create-team-channel-permission', 'User lacks create-team-channel permission for this team');
} Defensive patterns
Strategy: validation
Validate before calling
// Verify permissions and team existence before creating a channel
async function canCreateChannel(user, teamId) {
if (!teamId) {
return hasPermissionAsync(user._id, 'create-c');
}
const team = await Team.getInfoById(teamId);
if (!team) return { ok: false, reason: 'team-not-found' };
return { ok: await hasPermissionAsync(user._id, 'create-team-channel', team.roomId) };
} Type guard
function hasCreatePermissionFlags(perms) {
return Array.isArray(perms) && (perms.includes('create-c') || perms.includes('create-team-channel'));
} Try / catch
try {
await api.createChannel({ name, members, teamId });
} catch (e) {
if (e.message === 'unauthorized') {
notifyAdmin('Missing create-c or create-team-channel permission');
return;
}
throw e;
} Prevention
- 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.
When it happens
Trigger: 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).
Common situations: Custom role missing the create-c permission; teamId copied from a deleted team; role scope misconfiguration after a workspace migration.
Understand the failure class
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
- Param ${params.teams.key} must be an array
- error-not-authorized
- error-not-authorized
- error-not-allowed
- error-not-allowed
AI-assisted analysis of RocketChat/Rocket.Chat@f9d3ec372b (2026-08-12).
Data as JSON: /api/errors/fe50b87e122da6c9.
Report an issue: GitHub.