RocketChat/Rocket.Chat · error · Meteor.Error
error-permission-not-found
error-permission-not-found
Error message
Permission not found
What it means
Thrown when removing a role from a permission whose permissionId resolves to no document in the Permissions collection. Reached via DDP 'authorization:removeRoleFromPermission' or 'POST /api/v1/permissions.removeRole'. Unlike the add path there is no role existence check here, so this error is purely about the permission id.
Source
Thrown at apps/meteor/server/lib/authorization/permissionRole.ts:61
action: 'Adding_permission',
});
}
if (permission.groupPermissionId) {
await Permissions.addRole(permission.groupPermissionId, role);
void notifyOnPermissionChangedById(permission.groupPermissionId);
}
await Permissions.addRole(permission._id, role);
void notifyOnPermissionChangedById(permission._id);
};
export const removeRoleFromPermissionMethod = async (uid: string, permissionId: string, role: string): Promise<void> => {
const permission = await Permissions.findOneById(permissionId);
if (!permission) {
throw new Meteor.Error('error-permission-not-found', 'Permission not found', {
method: 'authorization:removeRoleFromPermission',
});
}
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', 'Removing permission is not allowed', {
method: 'authorization:removeRoleFromPermission',
action: 'Removing_permission',
});
}
if (permission.groupPermissionId) {
await Permissions.removeRole(permission.groupPermissionId, role);
void notifyOnPermissionChangedById(permission.groupPermissionId);
}View on GitHub (pinned to b2c16d5842)
Solutions
- Reload the permissions list so the client resends current ids, then retry
- Verify the permissionId against the live permission list before calling
- In mixed-version deployments, finish upgrading all nodes before editing permissions
- If automating, fetch permission ids at runtime instead of persisting them
Defensive patterns
Strategy: validation
Validate before calling
const known = new Set((await fetchPermissionsList()).map((p) => p._id));
if (!known.has(permissionId)) {
// refetch the permission list / abort instead of calling permissions.removeRole
} Try / catch
try {
await call('authorization:removeRoleFromPermission', permissionId, role);
} catch (e) {
if (e instanceof Meteor.Error && e.error === 'error-permission-not-found') {
// reload permissions metadata and retry once with fresh ids
} else {
throw e;
}
} Prevention
- Refetch permission metadata after every server upgrade
- Never persist permission ids across releases; re-resolve at runtime
- Automate permission changes only against a single, fully upgraded server version
When it happens
Trigger: The permissions screen holds a permission id that a Rocket.Chat upgrade renamed or removed (permission definitions change between versions); a script posts permissions.removeRole with a stale or hardcoded permissionId; mixed-version cluster where nodes hold different permission documents.
Common situations: Editing permissions right after an upgrade without a page reload; server downgrades; workspace restores where the Permissions collection drifted from the version's expected permission ids.
Related errors
AI-assisted analysis of RocketChat/Rocket.Chat@b2c16d5842 (2026-08-18).
Data as JSON: /api/errors/f4410a64ba265787.
Report an issue: GitHub.