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

  1. Grant the 'create-c' permission (or 'create-team-channel' scoped to the team) to the user's role in Administration > Permissions.
  2. Validate that teamId resolves to an existing team before calling create, so the permission check runs against a real scope.
  3. 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

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

Related errors


AI-assisted analysis of RocketChat/Rocket.Chat@f9d3ec372b (2026-08-12). Data as JSON: /api/errors/fe50b87e122da6c9. Report an issue: GitHub.