RocketChat/Rocket.Chat · error · MeteorError

error-invalid-scope

error-invalid-scope

Error message

Invalid scope

What it means

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.

Solutions

  1. Send exactly 'Users' or 'Subscriptions', or omit scope entirely to keep the current value.
  2. Validate the enum in the API schema (ajv) before the payload reaches updateRole.
  3. Trim and canonicalize the scope string client-side before submitting.

Example fix

// before
await updateRole(roleId, { scope: 'global' }); // throws error-invalid-scope

// after
await updateRole(roleId, { scope: 'Subscriptions' }); // or omit scope to keep current value
Defensive patterns

Strategy: validation

Validate before calling

if (roleData.scope !== undefined && roleData.scope !== 'Users' && roleData.scope !== 'Subscriptions') {
	// invalid scope; fix the payload or omit the field to keep the current value
}

Type guard

type RoleScope = 'Users' | 'Subscriptions';
const isRoleScope = (scope: unknown): scope is RoleScope => scope === 'Users' || scope === 'Subscriptions';

Try / catch

try {
	await updateRole(roleId, roleData);
} catch (e: any) {
	if (e?.error === 'error-invalid-scope') throw new Meteor.Error(400, "scope must be 'Users' or 'Subscriptions'");
	throw e;
}

Prevention

When it happens

Trigger: A role update payload carrying scope 'global', 'users' (case mismatch), 'Subscriptions ' (trailing space), or any free-text value instead of the two allowed literals.

Common situations: 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.

Understand the failure class

Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.

Related errors


AI-assisted analysis of RocketChat/Rocket.Chat@b2c16d5842 (2026-08-18). Data as JSON: /api/errors/175a76e5b4d30936. Report an issue: GitHub.

Appendix: source

Thrown at apps/meteor/ee/server/lib/roles/updateRole.ts:38

		throw new MeteorError('error-invalid-roleId', 'This role does not exist');
	}

	if (role.protected && ((roleData.name && roleData.name !== role.name) || (roleData.scope && roleData.scope !== role.scope))) {
		throw new MeteorError('error-role-protected', 'Role is protected');
	}

	if (roleData.name) {
		const otherRole = await Roles.findOneByName(roleData.name, { projection: { _id: 1 } });
		if (otherRole && otherRole._id !== role._id) {
			throw new MeteorError('error-duplicate-role-names-not-allowed', 'Role name already exists');
		}
	} else {
		roleData.name = role.name;
	}

	if (roleData.scope) {
		if (!isValidRoleScope(roleData.scope)) {
			throw new MeteorError('error-invalid-scope', 'Invalid scope');
		}
	} else {
		roleData.scope = role.scope;
	}

	await Roles.updateById(roleId, roleData.name, roleData.scope, roleData.description, roleData.mandatory2fa);

	void notifyOnRoleChangedById(roleId);

	if (options.broadcastUpdate) {
		void api.broadcast('user.roleUpdate', {
			type: 'changed',
			_id: roleId,
			scope: roleData.scope,
		});
	}

	const updatedRole = await Roles.findOneById(roleId);

View on GitHub (pinned to b2c16d5842)