RocketChat/Rocket.Chat · error · Meteor.Error
error-invalid-role
error-invalid-role
Error message
Role does not exist
What it means
Thrown by Rocket.Chat's authorization layer when a request attaches a role to a permission but the `role` argument matches no document in the Roles collection. Reached via DDP method 'authorization:addPermissionToRole' or REST 'POST /api/v1/permissions.addRole' (both call addPermissionToRoleMethod). The permission is looked up first, so this error specifically means permissionId was valid but the role id was not.
Source
Thrown at apps/meteor/server/lib/authorization/permissionRole.ts:31
if (AuthorizationUtils.isPermissionRestrictedForRole(permissionId, role)) {
throw new Meteor.Error('error-action-not-allowed', 'Permission is restricted', {
method: 'authorization:addPermissionToRole',
action: 'Adding_permission',
});
}
const permission = await Permissions.findOneById(permissionId);
if (!permission) {
throw new Meteor.Error('error-invalid-permission', 'Permission does not exist', {
method: 'authorization:addPermissionToRole',
action: 'Adding_permission',
});
}
if (!(await Roles.findOneById(role, { projection: { _id: 1 } }))) {
throw new Meteor.Error('error-invalid-role', 'Role does not exist', {
method: 'authorization:addPermissionToRole',
action: 'Adding_permission',
});
}
if (
!(await hasPermissionAsync(uid, 'access-permissions')) ||
(permission.level === CONSTANTS.SETTINGS_LEVEL && !(await hasPermissionAsync(uid, 'access-setting-permissions')))
) {
throw new Meteor.Error('error-action-not-allowed', 'Adding permission is not allowed', {
method: 'authorization:addPermissionToRole',
action: 'Adding_permission',
});
}
if (permission.groupPermissionId) {
await Permissions.addRole(permission.groupPermissionId, role);
void notifyOnPermissionChangedById(permission.groupPermissionId);View on GitHub (pinned to b2c16d5842)
Solutions
- Re-fetch the current role list (GET /api/v1/roles.list or reload Administration > Permissions) and pass the live role _id, not its name or description
- If the role was deleted unintentionally, recreate it under Administration > Roles and retry
- Guard the call by verifying the role exists first (see validation code)
- In automation, resolve role ids at runtime instead of hardcoding them
Example fix
// before
await POST '/api/v1/permissions.addRole' { permissionId: 'ban-user', role: 'moderator' } // 'moderator' was deleted
// after
const role = (await GET '/api/v1/roles.list').roles.find((r) => r._id === 'moderator');
if (!role) throw new Error('Role was deleted - recreate it first');
await POST '/api/v1/permissions.addRole' { permissionId: 'ban-user', role: role._id }; Defensive patterns
Strategy: validation
Validate before calling
const res = await fetch('/api/v1/roles.list', { headers: { 'X-Auth-Token': token, 'X-User-Id': uid } }).then((r) => r.json());
if (!res.roles.some((r) => r._id === roleId)) {
// refresh role list / recreate role instead of calling permissions.addRole
} Type guard
const isRoleRef = (r: unknown): r is { _id: string; name?: string } =>
typeof r === 'object' && r !== null && typeof (r as { _id?: unknown })._id === 'string'; Try / catch
try {
await call('authorization:addPermissionToRole', permissionId, roleId);
} catch (e) {
if (e instanceof Meteor.Error && e.error === 'error-invalid-role') {
// refresh roles and re-prompt the admin
} else {
throw e;
}
} Prevention
- Resolve role ids from a fresh roles.list call in the same session that submits the change
- Treat role ids as opaque server identifiers; never synthesize them from names
- In multi-admin workspaces, reload the permissions screen right before saving
When it happens
Trigger: Calling permissions.addRole with the _id of a role that was deleted (e.g. a custom role removed by another admin); submitting from a stale Permissions admin screen; passing a role name/description where the role _id is expected; hardcoding a role id from another workspace or seed data that does not exist on this server.
Common situations: Two admins editing permissions concurrently (one deletes the role while the other's browser holds the old list); automation scripts provisioning permissions on a fresh install; workspaces restored from backup where custom roles were not migrated; role rename creating a new _id and invalidating stored references.
Related errors
AI-assisted analysis of RocketChat/Rocket.Chat@b2c16d5842 (2026-08-18).
Data as JSON: /api/errors/7faf25f56c36085e.
Report an issue: GitHub.