{"record":{"id":"175a76e5b4d30936","repo":"RocketChat/Rocket.Chat","slug":"error-invalid-scope-175a76","errorCode":"error-invalid-scope","errorMessage":"Invalid scope","messagePattern":"Invalid scope","errorType":"exception","errorClass":"MeteorError","httpStatus":null,"severity":"error","filePath":"apps/meteor/ee/server/lib/roles/updateRole.ts","lineNumber":38,"sourceCode":"\t\tthrow new MeteorError('error-invalid-roleId', 'This role does not exist');\n\t}\n\n\tif (role.protected && ((roleData.name && roleData.name !== role.name) || (roleData.scope && roleData.scope !== role.scope))) {\n\t\tthrow new MeteorError('error-role-protected', 'Role is protected');\n\t}\n\n\tif (roleData.name) {\n\t\tconst otherRole = await Roles.findOneByName(roleData.name, { projection: { _id: 1 } });\n\t\tif (otherRole && otherRole._id !== role._id) {\n\t\t\tthrow new MeteorError('error-duplicate-role-names-not-allowed', 'Role name already exists');\n\t\t}\n\t} else {\n\t\troleData.name = role.name;\n\t}\n\n\tif (roleData.scope) {\n\t\tif (!isValidRoleScope(roleData.scope)) {\n\t\t\tthrow new MeteorError('error-invalid-scope', 'Invalid scope');\n\t\t}\n\t} else {\n\t\troleData.scope = role.scope;\n\t}\n\n\tawait Roles.updateById(roleId, roleData.name, roleData.scope, roleData.description, roleData.mandatory2fa);\n\n\tvoid notifyOnRoleChangedById(roleId);\n\n\tif (options.broadcastUpdate) {\n\t\tvoid api.broadcast('user.roleUpdate', {\n\t\t\ttype: 'changed',\n\t\t\t_id: roleId,\n\t\t\tscope: roleData.scope,\n\t\t});\n\t}\n\n\tconst updatedRole = await Roles.findOneById(roleId);","sourceCodeStart":20,"sourceCodeEnd":56,"githubUrl":"https://github.com/RocketChat/Rocket.Chat/blob/f9d3ec372bb580fa8d036f94cf03925a478ef768/apps/meteor/ee/server/lib/roles/updateRole.ts#L20-L56","documentation":"Thrown by updateRole in updateRole.ts:38 when roleData.scope is supplied but isValidRoleScope returns false. Same validator as insert: scope must be 'Users' or 'Subscriptions'. MeteorError code 'error-invalid-scope'.","triggerScenarios":"Updating a role and passing a scope outside ['Users','Subscriptions']. Note: an empty/falsy scope is allowed (it falls through to roleData.scope = role.scope), only a non-empty invalid value triggers this.","commonSituations":"Caller passes scope: 'Rooms' or 'Global'; UI sends an empty-string scope that bypasses the falsy branch.","solutions":["Set scope to 'Users' or 'Subscriptions', or omit it to keep the current value.","Validate scope against the allowed enum before calling updateRole.","Catch MeteorError 'error-invalid-scope' and re-prompt."],"exampleFix":"// before\nawait updateRole(roleId, { scope: 'Rooms' });\n\n// after\nconst VALID = ['Users', 'Subscriptions'] as const;\nconst patch = rawScope && !VALID.includes(rawScope) ? { scope: 'Users' } : { scope: rawScope };\nawait updateRole(roleId, patch);","handlingStrategy":"validation","validationCode":"const VALID = ['Users', 'Subscriptions'] as const;\nif (roleData.scope && !VALID.includes(roleData.scope as any)) throw new Error('invalid scope');","typeGuard":"const isValidScope = (scope: unknown): scope is 'Users' | 'Subscriptions' =>\n  scope === 'Users' || scope === 'Subscriptions';","tryCatchPattern":"try { await updateRole(roleId, roleData); }\ncatch (e) {\n  if (e?.code === 'error-invalid-scope') { /* re-prompt */ return; }\n  throw e;\n}","preventionTips":["Omit scope to keep the existing value.","Constrain the scope input to the allowed enum."],"tags":["roles","validation","meteor-error"],"backgroundTag":null,"analyzedSha":"f9d3ec372bb580fa8d036f94cf03925a478ef768","analyzedAt":"2026-08-12T19:07:17.372Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}