{"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/b2c16d5842cbe6b69b59bdf6fc5e5f1afcd1f0b0/apps/meteor/ee/server/lib/roles/updateRole.ts#L20-L56","documentation":"The same isValidRoleScope gate on the update path: when roleData.scope is provided it must be exactly 'Users' or 'Subscriptions', otherwise updateRole throws MeteorError('error-invalid-scope', 'Invalid scope'). Omitting the field is safe - it is backfilled from the existing role (roleData.scope = role.scope) - so the error only fires on an explicitly supplied invalid value.","triggerScenarios":"A role update payload carrying scope 'global', 'users' (case mismatch), 'Subscriptions ' (trailing space), or any free-text value instead of the two allowed literals.","commonSituations":"Same causes as the insert variant: hand-built payloads, legacy scope vocabulary from imports, enum not enforced on the client, or form fields that let users type arbitrary scope strings.","solutions":["Send exactly 'Users' or 'Subscriptions', or omit scope entirely to keep the current value.","Validate the enum in the API schema (ajv) before the payload reaches updateRole.","Trim and canonicalize the scope string client-side before submitting."],"exampleFix":"// before\nawait updateRole(roleId, { scope: 'global' }); // throws error-invalid-scope\n\n// after\nawait updateRole(roleId, { scope: 'Subscriptions' }); // or omit scope to keep current value","handlingStrategy":"validation","validationCode":"if (roleData.scope !== undefined && roleData.scope !== 'Users' && roleData.scope !== 'Subscriptions') {\n\t// invalid scope; fix the payload or omit the field to keep the current value\n}","typeGuard":"type RoleScope = 'Users' | 'Subscriptions';\nconst isRoleScope = (scope: unknown): scope is RoleScope => scope === 'Users' || scope === 'Subscriptions';","tryCatchPattern":"try {\n\tawait updateRole(roleId, roleData);\n} catch (e: any) {\n\tif (e?.error === 'error-invalid-scope') throw new Meteor.Error(400, \"scope must be 'Users' or 'Subscriptions'\");\n\tthrow e;\n}","preventionTips":["Use a dropdown limited to 'Users' and 'Subscriptions' instead of free-text scope inputs.","Omit scope from partial-update payloads when it is not being changed.","Validate the enum client-side and at the API schema before server code runs."],"tags":["roles","permissions","validation","enum","enterprise"],"backgroundTag":"invalid-enum-value","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"}