RocketChat/Rocket.Chat · error · Meteor.Error
error-invalid-permission
error-invalid-permission
Error message
Permission does not exist
What it means
addPermissionToRoleMethod throws error-invalid-permission, 'Permission does not exist', when Permissions.findOneById(permissionId) returns null — the id is not present in the Permissions collection. That collection is populated from declared permissions on startup and via migrations, so an unknown id means the caller holds stale data.
Source
Thrown at apps/meteor/server/lib/authorization/permissionRole.ts:24
import { CONSTANTS, AuthorizationUtils } from '../../../app/authorization/lib';
import { notifyOnPermissionChangedById } from '../notifyListener';
export const addPermissionToRoleMethod = async (uid: string, permissionId: string, role: string): Promise<void> => {
if (role === 'guest' && !AuthorizationUtils.hasRestrictionsToRole(role) && (await License.hasValidLicense())) {
AuthorizationUtils.addRolePermissionWhiteList(role, await License.getGuestPermissions());
}
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',View on GitHub (pinned to b2c16d5842)
Solutions
- Use ids from the source of truth: db.permissions.find() or GET /api/v1/permissions, before calling
- Ensure the server fully started and migrations ran after upgrading (check the migrations collection / startup logs)
- Derive permission ids dynamically in scripts instead of hardcoding them
Defensive patterns
Strategy: validation
Validate before calling
const perm = await Permissions.findOneById(permissionId, { projection: { _id: 1 } });
if (!perm) {
throw new Error(`Unknown permission id: ${permissionId}`);
}
await addPermissionToRoleMethod(uid, permissionId, role); Type guard
const isKnownPermission = (p: IPermission | null | undefined): p is IPermission => !!p?._id;
Try / catch
try {
await addPermissionToRoleMethod(uid, permissionId, role);
} catch (e) {
if (e instanceof Meteor.Error && e.error === 'error-invalid-permission') {
// stale id: re-fetch the permission list and correct the id before retrying once
}
throw e;
} Prevention
- Always resolve permission ids from the live Permissions collection/API
- Ensure migrations completed after upgrades before syncing permission matrices
- Re-derive exported matrices against the target version's permission set on import
When it happens
Trigger: authorization:addPermissionToRole invoked with a permission id that no longer exists (removed by a downgrade or refactor), a typo'd id, or on a fresh database whose migrations have not yet inserted the permission set; also races immediately after upgrade.
Common situations: An admin tab left open across an upgrade/downgrade submits old permission ids; scripts export a role-permission matrix from one version and import into another; custom permission removed from code but still cached by clients.
Related errors
- error-action-not-allowed
- error-not-authorized
- error-not-allowed
- error-invalid-role
- error-action-not-allowed
AI-assisted analysis of RocketChat/Rocket.Chat@b2c16d5842 (2026-08-18).
Data as JSON: /api/errors/b265926438d2fbd6.
Report an issue: GitHub.