{"record":{"id":"b265926438d2fbd6","repo":"RocketChat/Rocket.Chat","slug":"error-invalid-permission","errorCode":"error-invalid-permission","errorMessage":"Permission does not exist","messagePattern":"Permission does not exist","errorType":"exception","errorClass":"Meteor.Error","httpStatus":null,"severity":"error","filePath":"apps/meteor/server/lib/authorization/permissionRole.ts","lineNumber":24,"sourceCode":"import { CONSTANTS, AuthorizationUtils } from '../../../app/authorization/lib';\nimport { notifyOnPermissionChangedById } from '../notifyListener';\n\nexport const addPermissionToRoleMethod = async (uid: string, permissionId: string, role: string): Promise<void> => {\n\tif (role === 'guest' && !AuthorizationUtils.hasRestrictionsToRole(role) && (await License.hasValidLicense())) {\n\t\tAuthorizationUtils.addRolePermissionWhiteList(role, await License.getGuestPermissions());\n\t}\n\n\tif (AuthorizationUtils.isPermissionRestrictedForRole(permissionId, role)) {\n\t\tthrow new Meteor.Error('error-action-not-allowed', 'Permission is restricted', {\n\t\t\tmethod: 'authorization:addPermissionToRole',\n\t\t\taction: 'Adding_permission',\n\t\t});\n\t}\n\n\tconst permission = await Permissions.findOneById(permissionId);\n\n\tif (!permission) {\n\t\tthrow new Meteor.Error('error-invalid-permission', 'Permission does not exist', {\n\t\t\tmethod: 'authorization:addPermissionToRole',\n\t\t\taction: 'Adding_permission',\n\t\t});\n\t}\n\n\tif (!(await Roles.findOneById(role, { projection: { _id: 1 } }))) {\n\t\tthrow new Meteor.Error('error-invalid-role', 'Role does not exist', {\n\t\t\tmethod: 'authorization:addPermissionToRole',\n\t\t\taction: 'Adding_permission',\n\t\t});\n\t}\n\n\tif (\n\t\t!(await hasPermissionAsync(uid, 'access-permissions')) ||\n\t\t(permission.level === CONSTANTS.SETTINGS_LEVEL && !(await hasPermissionAsync(uid, 'access-setting-permissions')))\n\t) {\n\t\tthrow new Meteor.Error('error-action-not-allowed', 'Adding permission is not allowed', {\n\t\t\tmethod: 'authorization:addPermissionToRole',","sourceCodeStart":6,"sourceCodeEnd":42,"githubUrl":"https://github.com/RocketChat/Rocket.Chat/blob/b2c16d5842cbe6b69b59bdf6fc5e5f1afcd1f0b0/apps/meteor/server/lib/authorization/permissionRole.ts#L6-L42","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"const perm = await Permissions.findOneById(permissionId, { projection: { _id: 1 } });\nif (!perm) {\n  throw new Error(`Unknown permission id: ${permissionId}`);\n}\nawait addPermissionToRoleMethod(uid, permissionId, role);","typeGuard":"const isKnownPermission = (p: IPermission | null | undefined): p is IPermission => !!p?._id;","tryCatchPattern":"try {\n  await addPermissionToRoleMethod(uid, permissionId, role);\n} catch (e) {\n  if (e instanceof Meteor.Error && e.error === 'error-invalid-permission') {\n    // stale id: re-fetch the permission list and correct the id before retrying once\n  }\n  throw e;\n}","preventionTips":["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"],"tags":["authorization","permissions","roles","admin","database"],"backgroundTag":"permission-not-found","analyzedSha":"b2c16d5842cbe6b69b59bdf6fc5e5f1afcd1f0b0","analyzedAt":"2026-08-18T15:26:39.429Z","schemaVersion":2},"datasetVersion":"2026-08-21T13:17:26.733Z"}