{"record":{"id":"7faf25f56c36085e","repo":"RocketChat/Rocket.Chat","slug":"error-invalid-role","errorCode":"error-invalid-role","errorMessage":"Role does not exist","messagePattern":"Role does not exist","errorType":"exception","errorClass":"Meteor.Error","httpStatus":null,"severity":"error","filePath":"apps/meteor/server/lib/authorization/permissionRole.ts","lineNumber":31,"sourceCode":"\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',\n\t\t\taction: 'Adding_permission',\n\t\t});\n\t}\n\n\tif (permission.groupPermissionId) {\n\t\tawait Permissions.addRole(permission.groupPermissionId, role);\n\t\tvoid notifyOnPermissionChangedById(permission.groupPermissionId);","sourceCodeStart":13,"sourceCodeEnd":49,"githubUrl":"https://github.com/RocketChat/Rocket.Chat/blob/b2c16d5842cbe6b69b59bdf6fc5e5f1afcd1f0b0/apps/meteor/server/lib/authorization/permissionRole.ts#L13-L49","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nawait POST '/api/v1/permissions.addRole' { permissionId: 'ban-user', role: 'moderator' } // 'moderator' was deleted\n\n// after\nconst role = (await GET '/api/v1/roles.list').roles.find((r) => r._id === 'moderator');\nif (!role) throw new Error('Role was deleted - recreate it first');\nawait POST '/api/v1/permissions.addRole' { permissionId: 'ban-user', role: role._id };","handlingStrategy":"validation","validationCode":"const res = await fetch('/api/v1/roles.list', { headers: { 'X-Auth-Token': token, 'X-User-Id': uid } }).then((r) => r.json());\nif (!res.roles.some((r) => r._id === roleId)) {\n  // refresh role list / recreate role instead of calling permissions.addRole\n}","typeGuard":"const isRoleRef = (r: unknown): r is { _id: string; name?: string } =>\n  typeof r === 'object' && r !== null && typeof (r as { _id?: unknown })._id === 'string';","tryCatchPattern":"try {\n  await call('authorization:addPermissionToRole', permissionId, roleId);\n} catch (e) {\n  if (e instanceof Meteor.Error && e.error === 'error-invalid-role') {\n    // refresh roles and re-prompt the admin\n  } else {\n    throw e;\n  }\n}","preventionTips":["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"],"tags":["rocket-chat","authorization","permissions","roles","meteor-methods","rest-api"],"backgroundTag":"role-not-found","analyzedSha":"b2c16d5842cbe6b69b59bdf6fc5e5f1afcd1f0b0","analyzedAt":"2026-08-18T15:26:39.429Z","schemaVersion":2},"datasetVersion":"2026-08-21T13:17:26.733Z"}