{"record":{"id":"8454985b0ec9460c","repo":"RocketChat/Rocket.Chat","slug":"error-role-protected-845498","errorCode":"error-role-protected","errorMessage":"Cannot delete a protected role","messagePattern":"Cannot delete a protected role","errorType":"exception","errorClass":"Meteor.Error","httpStatus":400,"severity":"error","filePath":"apps/meteor/server/api/v1/roles.ts","lineNumber":243,"sourceCode":"\t\t\t\t\trequired: ['success'],\n\t\t\t\t\tadditionalProperties: false,\n\t\t\t\t}),\n\t\t\t\t400: validateBadRequestErrorResponse,\n\t\t\t\t401: validateUnauthorizedErrorResponse,\n\t\t\t\t403: validateForbiddenErrorResponse,\n\t\t\t},\n\t\t},\n\t\tasync function action() {\n\t\t\tconst { bodyParams } = this;\n\n\t\t\tconst role = await Roles.findOneByIdOrName(bodyParams.roleId);\n\n\t\t\tif (!role) {\n\t\t\t\tthrow new Meteor.Error('error-invalid-roleId', 'This role does not exist');\n\t\t\t}\n\n\t\t\tif (role.protected) {\n\t\t\t\tthrow new Meteor.Error('error-role-protected', 'Cannot delete a protected role');\n\t\t\t}\n\n\t\t\tif ((await Roles.countUsersInRole(role._id)) > 0) {\n\t\t\t\tthrow new Meteor.Error('error-role-in-use', \"Cannot delete role because it's in use\");\n\t\t\t}\n\n\t\t\tawait Roles.removeById(role._id);\n\n\t\t\tvoid notifyOnRoleChanged(role, 'removed');\n\n\t\t\treturn API.v1.success();\n\t\t},\n\t)\n\t.post(\n\t\t'roles.removeUserFromRole',\n\t\t{\n\t\t\tauthRequired: true,\n\t\t\tpermissionsRequired: ['access-permissions'],","sourceCodeStart":225,"sourceCodeEnd":261,"githubUrl":"https://github.com/RocketChat/Rocket.Chat/blob/b2c16d5842cbe6b69b59bdf6fc5e5f1afcd1f0b0/apps/meteor/server/api/v1/roles.ts#L225-L261","documentation":"Thrown by POST /api/v1/roles.delete when the target role has its `protected` flag set. Rocket.Chat marks built-in roles (admin, user, bot, moderator, owner, leader, livechat-agent, and similar system roles) as protected because core authorization logic depends on them; the delete flow refuses to remove them regardless of permissions.","triggerScenarios":"POST /api/v1/roles.delete { roleId: <id-or-name> } targeting any built-in role — e.g. 'admin', 'moderator', 'livechat-agent'. The role resolves fine, but role.protected is true in the database, so the guard fires before the in-use check.","commonSituations":"Cleanup scripts trying to 'reset' a workspace by deleting default roles; admins attempting to hide a built-in role by deleting it; migrations that assume all roles are deletable.","solutions":["Don't delete built-in roles — filter them out of any automated cleanup (check the protected field from roles.list)","To stop a built-in role being assignable, manage its permissions instead of deleting the role","If you need a variant, create a custom role rather than repurposing a protected one"],"exampleFix":"// before\nawait sdk.post('roles.delete', { roleId });\n\n// after (never attempt protected roles)\nconst role = roles.find((r) => r._id === roleId || r.name === roleId);\nif (role?.protected) throw new Error(`role ${role.name} is protected and cannot be deleted`);\nawait sdk.post('roles.delete', { roleId });","handlingStrategy":"validation","validationCode":"const { roles } = await sdk.get('roles.list');\nconst target = roles.find((r) => r._id === roleId || r.name === roleId);\nif (target?.protected) {\n  throw new Error(`role '${target.name}' is protected — manage its permissions instead of deleting it`);\n}\nawait sdk.post('roles.delete', { roleId: target?._id ?? roleId });","typeGuard":"const isProtectedRole = (role: { protected?: boolean } | undefined): boolean =>\n  role?.protected === true;","tryCatchPattern":"catch 'error-role-protected' and skip permanently — the guard is intentional and no retry or permission change will bypass it; adjust your cleanup list to exclude built-in roles.","preventionTips":["Filter roles.list results by !protected before offering deletion in UIs/scripts","Treat built-in roles as configuration to adjust (permissions), not resources to delete","Document which roles ship protected so operators don't try"],"tags":["roles","protected-resources","permissions","rest-api","lifecycle"],"backgroundTag":"protected-resource-delete","analyzedSha":"b2c16d5842cbe6b69b59bdf6fc5e5f1afcd1f0b0","analyzedAt":"2026-08-18T15:26:39.429Z","contentChangedAt":"2026-08-18T15:26:39.429Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}